mirror of
https://codeberg.org/la-chouette/minishell.git
synced 2025-12-05 23:18:08 +01:00
Compare commits
8 commits
ff3dfe3b84
...
083a2bb2a2
| Author | SHA1 | Date | |
|---|---|---|---|
| 083a2bb2a2 | |||
|
|
ee10abacab | ||
|
|
8b43fd2411 | ||
| a7f09137ee | |||
| 5e8edb9a99 | |||
| 313bef63fd | |||
| b7e48cca05 | |||
| 52c33abb16 |
103 changed files with 148 additions and 5527 deletions
3
Makefile
3
Makefile
|
|
@ -17,7 +17,7 @@ LINCLUDE = -L$(LIBFTDIR)
|
|||
|
||||
ifeq ($(CFLAGS),)
|
||||
CFLAGS = -Wall -Wextra -Werror \
|
||||
$(DEBUG) \
|
||||
$(DEBUG) \
|
||||
|
||||
endif
|
||||
export CFLAGS
|
||||
|
|
@ -157,7 +157,6 @@ clean:
|
|||
fclean: clean
|
||||
$(MAKE) -C $(LIBFTDIR) fclean
|
||||
rm -f $(NAME)
|
||||
+make -C tests fclean
|
||||
|
||||
re:
|
||||
+make fclean
|
||||
|
|
|
|||
744
NOTES.md
744
NOTES.md
|
|
@ -1,744 +0,0 @@
|
|||
# Notes relatives au projet
|
||||
|
||||
cf. [Bash Reference Manual](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html)
|
||||
|
||||
Comparative testing with bash should be done with bash --norc.
|
||||
|
||||
In case of difference between regular bash and posix bash, we decide to follow regular bash.
|
||||
|
||||
## Ideas for testing
|
||||
* use prysk or shellspec with shell=./minishell
|
||||
|
||||
### Prysk
|
||||
Seems like it would work, but only after we implement execution of simple commands, and the $? variable, since prysk (and cram as well) relie on it to collect the exit status.
|
||||
|
||||
For it to work, the shell must be able to execute the following command:
|
||||
```shell
|
||||
$ echo PRYSK12345 2 $?
|
||||
PRYSK12345 2 0
|
||||
```
|
||||
|
||||
## Usefull resources
|
||||
|
||||
[Bash Reference Manual](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html)
|
||||
|
||||
[Internal parsing & flow](https://mail.gnu.org/archive/html/help-bash/2014-01/msg00000.html)
|
||||
|
||||
[Python parser for bash](https://github.com/idank/bashlex)
|
||||
|
||||
[The Stages of Word Expansion](https://www.gnu.org/software/libc/manual/html_node/Expansion-Stages.html)
|
||||
|
||||
[Diagram of bash parse flow](https://web.archive.org/web/20160308045823/https://stuff.lhunath.com/parser.png)
|
||||
|
||||
[The Bash Parser](http://mywiki.wooledge.org/BashParser)
|
||||
|
||||
[The Architecture of Open Source Applications (Volume 1) The Bourne-Again Shell](https://aosabook.org/en/v1/bash.html)
|
||||
|
||||
[IEEE Open Group Base Specification Issue 7: Shell Command Language](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_01)
|
||||
|
||||
[The Bash Hackers Wiki: Basic grammar rules of Bash (see also other pages on this website)](https://bash-hackers.gabe565.com/syntax/basicgrammar/)
|
||||
|
||||
## Shell Operation
|
||||
|
||||
cf. 3.1.1 Shell Operation
|
||||
|
||||
Reads the input. When reading input in non-interactive mode, it MUST do so one
|
||||
character at a time, so that it does not accidentally read a character that is
|
||||
intended for a called program.
|
||||
|
||||
Breaks the input into **words** and **operators**, obeying the *Quoting Rules*.
|
||||
These tokens are delimited by **metacharacters**.
|
||||
|
||||
Parses the tokens into simple and compound commands (see *Shell Commands*)
|
||||
|
||||
Performs the various _Shell Expansions_, breaking the expanded tokens into lists
|
||||
of filenames and commands and arguments.
|
||||
|
||||
Performs any necessary _redirections_ and removes the **redirection operators**
|
||||
and their operands from the argument list.
|
||||
|
||||
Executes the command (see _Command Execution_);
|
||||
|
||||
Waits for the command to complete and collects its exit status (see _Exit Status_).
|
||||
|
||||
### Quoting Rules
|
||||
|
||||
cf. 3.1.2 Quoting
|
||||
|
||||
Quoting escapes metacharacters.
|
||||
|
||||
The quoting mechanisms we have to implement are:
|
||||
|
||||
cf. Subject
|
||||
|
||||
* Single quotes, which prevent metacharacters interpretation.
|
||||
* Double quotes, which prevent metacharacters interpretation except for '$' (See
|
||||
_Shell Parameter Expansion_).
|
||||
|
||||
In the Bash Reference Manual, these are defined as follows (keeping only the parts we have to implement):
|
||||
|
||||
cf. 3.1.2.2 Single Quotes
|
||||
|
||||
Preserves the literal value of each character within the quotes.
|
||||
|
||||
cf. 3.1.2.3 Double Quotes
|
||||
|
||||
Preserves the literal value of all characters within the quotes, with the exception of '$'.
|
||||
|
||||
Per the subject: minishell should not interpret unclosed quotes
|
||||
|
||||
### Shell Commands
|
||||
|
||||
cf. 3.2 Shell Commands
|
||||
|
||||
A Shell Command may be either a *Simple Command*, a *Pipeline*, a *List of
|
||||
Commands* (composed of one or more *Pipelines*), or a *Grouped Command*
|
||||
(composed of one or more *List of Commands*).
|
||||
|
||||
#### Simple Commands
|
||||
|
||||
cf. 3.2.2 Simple Commands
|
||||
|
||||
It’s just a sequence of words separated by **blanks**, terminated by one of the
|
||||
shell’s **control operators**.
|
||||
The first **word** specifies a command to be executed, with the rest of the
|
||||
**words** being that command’s arguments.
|
||||
|
||||
The return status (see _Exit Status_) of a simple command is its exit status as
|
||||
provided by the POSIX 1003.1 waitpid function, or 128+n if the command was
|
||||
terminated by signal n.
|
||||
|
||||
#### Pipelines
|
||||
|
||||
cf. 3.2.3 Pipelines
|
||||
|
||||
A pipeline is a sequence of one or more commands separated by the control operator '|'.
|
||||
|
||||
The output of each command in the pipeline is connected via a pipe to the input
|
||||
of the next command.
|
||||
That is, each command reads the previous command’s output.
|
||||
This connection is performed before any redirections specified by the first
|
||||
command.
|
||||
|
||||
The shell waits for all commands in the pipeline to complete before reading the next command.
|
||||
|
||||
Each command in a multi-command pipeline, where pipes are created, is executed
|
||||
in its own _subshell_, which is a separate process.
|
||||
|
||||
e.g.
|
||||
|
||||
```shell
|
||||
export TT=1 | echo $TT
|
||||
```
|
||||
|
||||
prints an empty string, because TT is unset in the second subshell.
|
||||
|
||||
The exit status of a pipeline is the exit status of the last command in the pipeline.
|
||||
|
||||
The shell waits for all commands in the pipeline to terminate before returning a value.
|
||||
|
||||
#### Lists of Commands
|
||||
|
||||
cf. 3.2.4 Lists of Commands
|
||||
|
||||
A list is a sequence of one or more pipelines separated by one of the
|
||||
**operators** ‘&&’, or ‘||’, and optionally terminated by a newline.
|
||||
|
||||
AND and OR lists are sequences of one or more pipelines separated by the control
|
||||
operators ‘&&’ and ‘||’, respectively.
|
||||
AND and OR lists are executed with left associativity.
|
||||
|
||||
e.g.
|
||||
|
||||
```shell
|
||||
A && B && C
|
||||
```
|
||||
|
||||
is the same as
|
||||
|
||||
```shell
|
||||
(A && B) && C
|
||||
```
|
||||
|
||||
An AND list has the form
|
||||
|
||||
```shell
|
||||
A && B
|
||||
```
|
||||
|
||||
B is execute if and only if A has an exit status of 0 (succes).
|
||||
|
||||
An OR list has the form
|
||||
|
||||
```shell
|
||||
A || B
|
||||
```
|
||||
|
||||
B is execute if and only if A has a non-zero exit status (failure).
|
||||
|
||||
The return status of AND and OR lists is the exit status of the last command
|
||||
executed in the list.
|
||||
|
||||
#### Group of Commands
|
||||
|
||||
cf. 3.2.5 Compound Commands
|
||||
|
||||
Each group begins with the **control operator** '(' and ends with the
|
||||
**control operator** ')'.
|
||||
|
||||
Any redirections associated with a _group of commands_ apply to all commands
|
||||
within that _group of commands_ unless explicitly overridden.
|
||||
|
||||
cf. 3.2.5.3 Grouping Commands
|
||||
|
||||
When commands are grouped, redirections may be applied to the entire command
|
||||
list. For example, the output of all the commands in the list may be redirected
|
||||
to a single stream.
|
||||
|
||||
( LIST )
|
||||
|
||||
The parentheses are operators, and are recognized as separate tokens by the
|
||||
shell even if they are not separated from the LIST by whitespace.
|
||||
|
||||
Placing a list of commands between parentheses forces the shell to create a
|
||||
_subshell, and each of the commands in LIST is executed in that subshell
|
||||
environment. Since the LIST is executed in a subshell, variable assignments do
|
||||
not remain in effect after the subshell completes.
|
||||
|
||||
The exit status of this construct is the exit status of LIST.
|
||||
|
||||
```c
|
||||
typedef enum e_cmdlist_item_type
|
||||
{
|
||||
TYPE_INVALID,
|
||||
TYPE_CMDGROUP,
|
||||
TYPE_PIPELINE,
|
||||
} t_cmdlist_item_type;
|
||||
|
||||
typedef struct s_cmdlist_item
|
||||
{
|
||||
enum e_cmdlist_item_type type;
|
||||
union u_cmdlist_item_inner
|
||||
{
|
||||
t_cmdgroup *cmdgroup;
|
||||
struct s_pipeline *pipeline;
|
||||
} inner;
|
||||
} t_cmdlist_item;
|
||||
|
||||
typedef s_cmdlist
|
||||
{
|
||||
struct s_cmdlist_item *cmds;
|
||||
int num_cmds;
|
||||
struct s_operators *operators;
|
||||
} t_cmdlist;
|
||||
|
||||
typedef struct s_cmdgroup
|
||||
{
|
||||
struct s_cmdlist item;
|
||||
struct s_redirection_list *redirections;
|
||||
} t_cmdgroup;
|
||||
```
|
||||
|
||||
```c
|
||||
// (cmd1) && (cmd2)
|
||||
|
||||
t_cmdgroup
|
||||
{
|
||||
item = t_cmdlist
|
||||
{
|
||||
cmds = [
|
||||
t_cmdlist_item
|
||||
{
|
||||
type = TYPE_CMDGROUP
|
||||
inner = t_cmdgroup
|
||||
{
|
||||
item = t_cmdlist
|
||||
{
|
||||
cmds = [
|
||||
t_cmdlist_item
|
||||
{
|
||||
type = TYPE_PIPELINE
|
||||
inner = t_pipeline "cmd1"
|
||||
}
|
||||
]
|
||||
num_cmds = 1
|
||||
operators = [OP_END]
|
||||
}
|
||||
redirections = NULL
|
||||
}
|
||||
}
|
||||
t_cmdlist_item
|
||||
{
|
||||
type = TYPE_CMDGROUP
|
||||
inner = t_cmdgroup
|
||||
{
|
||||
item = t_cmdlist
|
||||
{
|
||||
cmds = [
|
||||
t_cmdlist_item
|
||||
{
|
||||
type = TYPE_PIPELINE
|
||||
inner = t_pipeline "cmd2"
|
||||
}
|
||||
]
|
||||
num_cmds = 1
|
||||
operators = [OP_END]
|
||||
}
|
||||
redirections = NULL
|
||||
}
|
||||
}
|
||||
]
|
||||
num_cmd = 2
|
||||
operators = [OP_AND, OP_END]
|
||||
}
|
||||
redirections = NULL
|
||||
}
|
||||
```
|
||||
|
||||
### Shell Expansion
|
||||
|
||||
cf. 3.5 Shell Expansions
|
||||
|
||||
Expansion is performed on the command line after it has been split into
|
||||
**token**'s. There are seven kinds of expansion performed. in the following
|
||||
order:
|
||||
|
||||
* brace expansion
|
||||
* tilde expansion
|
||||
* parameter and variable expansion
|
||||
* arithmetic expansion
|
||||
* command substitution (left to right)
|
||||
* word splitting
|
||||
* filename expansion
|
||||
|
||||
We only have to implement the following kinds:
|
||||
* parameter expansion
|
||||
* word splitting
|
||||
* filename expansion
|
||||
|
||||
After these expansions are performed, quote characters present in the original
|
||||
word are removed unless they have been quoted themselves ("_quote removal_").
|
||||
|
||||
Only brace expansion, word splitting, and filename expansion can increase the
|
||||
number of words of the expansion; other expansions expand a single word to a
|
||||
single word.
|
||||
|
||||
#### Shell Parameter Expansion
|
||||
cf. 3.5.3 Shell Parameter Expansion
|
||||
|
||||
The '$' character introduces parameter expansion, command substitution, or
|
||||
arithmetic expansion.
|
||||
|
||||
The form is $VAR, where VAR may only contain the following characters:
|
||||
* a-z
|
||||
* A-Z
|
||||
* _
|
||||
* 0-9 (not in the first character)
|
||||
|
||||
Just noticed an interesting case:
|
||||
```shell
|
||||
bash-5.2$ VAR=hello # we set a shell variable (NOT environment variable)
|
||||
bash-5.2$ VAR=hi env | grep VAR=; env | grep VAR= # here VAR is an environment variable, which is only valid for the next command (the second env returns nothing, confirming that it is not valid for that command)
|
||||
VAR=hi
|
||||
bash-5.2$ env | grep VAR= # var is not an environment variable
|
||||
bash-5.2$ echo $VAR # but it is a shell variable
|
||||
hello
|
||||
```
|
||||
Luckily for us, we don't have to handle shell variables, nor do we have to handle `VAR=value` or `VAR=value cmd`.
|
||||
|
||||
#### Word Splitting
|
||||
cf. 3.5.7 Word Splitting
|
||||
|
||||
The shell scans the results of parameter expansion that did not occur within
|
||||
double quotes for word splitting.
|
||||
|
||||
The shell splits the results of the other expansions into **words**.
|
||||
|
||||
The shell treats the following characters as a delimiter:
|
||||
* (space)
|
||||
* (tab)
|
||||
* (newline)
|
||||
|
||||
Explicit null arguments ('""' or '''') are retained and passed to commands as
|
||||
empty strings. Unquoted implicit null arguments, resulting from the expansion
|
||||
of parameters that have no values, are removed. If a parameter with no value is
|
||||
expanded within double quotes, a null argument results and is retained and
|
||||
passed to a command as an empty string. When a quoted null argument appears as
|
||||
part of a word whose expansion is non-null, the null argument is removed. That
|
||||
is, the word '-d''' becomes '-d' after word splitting and null argument removal.
|
||||
|
||||
Note that if no expansion occurs, no splitting is performed.
|
||||
|
||||
#### Filename Expansion
|
||||
cf. 3.5.8 Filename Expansion
|
||||
|
||||
Bash scans each word for the character '\*'.
|
||||
|
||||
If one of these characters appears, and is not quoted, then the word is regarded
|
||||
as a PATTERN, and replaced with an alphabetically sorted list of filenames
|
||||
matching the pattern (see: _Pattern Matching_). If no matching filenames are
|
||||
found, the word is left unchanged.
|
||||
|
||||
When a pattern is used for filename expansion, the character '.' at the start of
|
||||
a filename or immediately following a slash must be matched explicitly. In order
|
||||
to match the filenames '.' and '..', the pattern must begin with '.'
|
||||
|
||||
When matching a filename, the slash character must always be matched explicitly
|
||||
by a slash in the pattern.
|
||||
|
||||
##### Pattern Matching
|
||||
cf. 3.5.8.1 Pattern Matching
|
||||
|
||||
Any character that appears in a pattern, other than the special pattern
|
||||
characters described below, matches itself. The NUL character may not occur in
|
||||
a pattern.
|
||||
|
||||
The special pattern characters have the following meanings:
|
||||
'\*'
|
||||
Matches any string, including the null string.
|
||||
|
||||
The special pattern characters must be quoted if they are to be matched
|
||||
literally.
|
||||
|
||||
e.g. this is the required behaviour
|
||||
```shell
|
||||
bash-5.1$ ls *there
|
||||
'hello*there' 'hi*there' noonethere
|
||||
bash-5.1$ ls *'*'there
|
||||
'hello*there' 'hi*there'
|
||||
```
|
||||
|
||||
#### Quote Removal
|
||||
cf. 3.5.9 Quote Removal
|
||||
|
||||
After the preceding expansions, all unquoted occurrences of the characters '''
|
||||
and '"' that did not result from one of the above expansions are removed.
|
||||
|
||||
### Redirection
|
||||
cf. 3.6 Redirections
|
||||
|
||||
Before a command is executed, its input and output may be "redirected" using a
|
||||
special notation interpreted by the shell. "Redirection" allows commands' file
|
||||
handles to be made to refer to different files, and can change the files the
|
||||
command reads from and writes to.
|
||||
|
||||
The redirection operators may precede or appear anywhere within a simple command
|
||||
or may follow a command.
|
||||
|
||||
e.g. this is the correct behaviour
|
||||
```shell
|
||||
bash-5.1$ ls > hello.txt *here
|
||||
bash-5.1$ cat hello.txt
|
||||
hello*there
|
||||
hi*there
|
||||
noonethere
|
||||
```
|
||||
|
||||
Redirections are processed in the order they appear, from left to right.
|
||||
|
||||
e.g. this is the correct behaviour
|
||||
```shell
|
||||
bash-5.1$ ls > hello.txt share > here.txt *.txt
|
||||
bash-5.1$ ls -l hello.txt here.txt
|
||||
-rw-r--r-- 1 kcolin 2024_le-havre 0 Feb 7 15:54 hello.txt
|
||||
-rw-r--r-- 1 kcolin 2024_le-havre 68 Feb 7 15:54 here.txt
|
||||
bash-5.1$ cat here.txt
|
||||
hello.txt
|
||||
here.txt
|
||||
log.txt
|
||||
newlog-strict.txt
|
||||
newlog.txt
|
||||
|
||||
share:
|
||||
man
|
||||
```
|
||||
|
||||
'<' refers to the standard input (fd 0, STDIN\_FILENO)
|
||||
|
||||
'>' refers to the standard output (fd 1, STDOUT\_FILENO)
|
||||
|
||||
The word following the redirection operator, unless the redirection operator is
|
||||
'<<', is subjected to parameter expansion, filename expansion, word splitting,
|
||||
and quote removal.
|
||||
|
||||
If it expands to more than one word, Bash reports an error.
|
||||
|
||||
This is the correct behaviour:
|
||||
```shell
|
||||
bash-5.1$ var="file1 file2"
|
||||
bash-5.1$ echo "hello world" > $var
|
||||
bash: $var: ambiguous redirect
|
||||
```
|
||||
|
||||
If the variable is not defined, bash prints the following error:
|
||||
|
||||
```shell
|
||||
bash-5.1$ echo "hello world" > $nonexist
|
||||
bash: $nonexist: ambiguous redirect
|
||||
```
|
||||
|
||||
Interesting cases:
|
||||
command group must handle redirections at the scale of the group
|
||||
pipelines handle piplines
|
||||
simple commands handle its own file redirections
|
||||
group redirections may not appear at the start, except for here_doc, which will give a parse error *afterwards*
|
||||
```shell
|
||||
bash-5.2$ (echo hello | cat -e > outcat && echo hi) > outgroup
|
||||
bash-5.2$ cat outgroup
|
||||
hi
|
||||
bash-5.2$ cat outcat
|
||||
hello$
|
||||
bash-5.2$ (echo hello | cat -e && echo hi) > outgroup2
|
||||
bash-5.2$ cat outgroup2
|
||||
hello$
|
||||
hi
|
||||
bash-5.2$ (echo hello > outhello | cat -e && echo hi) > outgroup3
|
||||
bash-5.2$ cat outhello
|
||||
hello
|
||||
bash-5.2$ cat outgroup3
|
||||
hi
|
||||
bash-5.2$ > outgroup4 (echo hello > outhello | cat -e && echo hi)
|
||||
bash: syntax error near unexpected token `('
|
||||
bash-5.2$ echo bonjour > infile
|
||||
bash-5.2$ < infile (cat - > outhello | cat -e && echo hi)
|
||||
bash: syntax error near unexpected token `('
|
||||
bash-5.2$ << EOF (cat - > outhello | cat -e && echo hi)
|
||||
> hello
|
||||
> EOF
|
||||
bash: syntax error near unexpected token `('
|
||||
bash-5.2$ (cat - > outhello | cat -e && echo hi) < infile
|
||||
hi
|
||||
bash-5.2$ (cat - > outhello | cat -e && echo hi) << EOF
|
||||
> helllo
|
||||
> EOF
|
||||
hi
|
||||
bash-5.2$ cat outhello
|
||||
helllo
|
||||
bash-5.2$ (echo coucou | echo hello) > outfile
|
||||
bash-5.2$ cat outfile
|
||||
hello
|
||||
```
|
||||
|
||||
#### Here Documents
|
||||
cf. Bash Reference Manual 3.6.6 Here Documents
|
||||
|
||||
This type of redirection instructs the shell to read input from the current
|
||||
source until a line containing only word (with no trailing blanks) is seen. All
|
||||
of the lines read up to that point are then used as the standard input for a
|
||||
command.
|
||||
|
||||
No parameter and variable expansion, command substitution, arithmetic expansion,
|
||||
or filename expansion is performed on word.
|
||||
|
||||
If any part of word is quoted, the delimiter is the result of quote removal on
|
||||
word, and the lines in the here-document are not expanded. If word is unquoted,
|
||||
all lines of the here-document are subjected to parameter expansion.
|
||||
|
||||
This is the correct behaviour for quoting and parameter expansion:
|
||||
```shell
|
||||
bash-5.2$ cat << EOF
|
||||
> hello
|
||||
> $$
|
||||
> EOF
|
||||
hello
|
||||
1491742
|
||||
bash-5.2$ cat << "EOF"
|
||||
> hello
|
||||
> $$
|
||||
> EOF
|
||||
hello
|
||||
$$
|
||||
bash-5.2$ cat << 'E'OF
|
||||
> hello
|
||||
> $$
|
||||
> EOF
|
||||
hello
|
||||
$$
|
||||
bash-5.2$ cat << $USER
|
||||
> hello
|
||||
> khais
|
||||
> $USER
|
||||
hello
|
||||
khais
|
||||
bash-5.2$ echo $USER
|
||||
khais
|
||||
bash-5.2$ cat << "$USER"
|
||||
> $USER
|
||||
```
|
||||
|
||||
Subject says \\ is not required, so this behaviour we will not implement:
|
||||
```shell
|
||||
bash-5.2$ cat << EOF
|
||||
> hello \
|
||||
world
|
||||
> EOF
|
||||
hello world
|
||||
```
|
||||
|
||||
### Executing Commands
|
||||
cf. 3.7 Executing Commands
|
||||
|
||||
#### Simple Command Execution
|
||||
cf. 3.7.1 Simple Command Expansion
|
||||
|
||||
When a simple command is executed, the shell performs the following
|
||||
expansions, assignments, and redirections, from left to right, in the
|
||||
following order.
|
||||
|
||||
1. The words that the parser has marked as redirections are saved for later
|
||||
processing.
|
||||
|
||||
2. The words that are not redirections are expanded (see _Shell Expansions_).
|
||||
If any words remain after expansion, the first word is taken to be the name
|
||||
of the command and the remaining words are the arguments.
|
||||
|
||||
3. Redirections are performed as described above (see _Redirections_).
|
||||
|
||||
If no command name results, redirections are performed, but do not affect the
|
||||
current shell environment. A redirection error causes the command to exit with
|
||||
a non-zero status.
|
||||
|
||||
If there is a command name left after expansion, execution proceeds as described
|
||||
below. Otherwise, the command exits with a status of zero.
|
||||
|
||||
#### Command Search and Execution
|
||||
cf. 3.7.2 Command Search and Execution
|
||||
|
||||
After a command has been split into words, if it results in a simple command and
|
||||
an optional list of arguments, the following actions are taken.
|
||||
|
||||
1. The shell searches for it in the list of shell builtins. If a match is
|
||||
found, that builtin is invoked.
|
||||
|
||||
2. If the name is not a builtin, and contains no slashes, Bash searches each
|
||||
element of '$PATH' for a directory containing an executable file by that
|
||||
name. If the search is unsuccessful, the shell prints an error message and
|
||||
returns an exit status of 127.
|
||||
|
||||
3. If the search is successful, or if the command name contains one or more
|
||||
slashes, the shell executes the named program in a separate execution
|
||||
environment. Argument 0 is set to the name given, and the remaining
|
||||
arguments to the command are set to the arguments supplied, if any.
|
||||
|
||||
4. If this execution fails because the file is not in executable format, and
|
||||
the file is not a directory, it is assumed to be a "shell script" and the
|
||||
shell executes it as described in _Shell Scripts_.
|
||||
|
||||
NOTE: we will _maybe_ implement this, we will see. It does not seem to be
|
||||
required.
|
||||
|
||||
5. The shell waits for the command to complete and collects its exit status.
|
||||
|
||||
#### Subshell
|
||||
cf. 3.7.3 Command Execution Environment
|
||||
|
||||
The shell has an execution environment, which consists of the following:
|
||||
|
||||
open files inherited by the shell at invocation, as modified by redirections
|
||||
|
||||
the current working directory as set by cd or inherited by the shell at invocation
|
||||
|
||||
shell variables, passed in the environment
|
||||
|
||||
A command invoked in this separate environment cannot affect the shell’s
|
||||
execution environment.
|
||||
|
||||
A subshell is a copy of the shell process.
|
||||
|
||||
#### Environment
|
||||
cf. 3.7.4 Environment
|
||||
|
||||
When a program is invoked it is given an array of strings called the
|
||||
"environment". This is a list of name-value pairs, of the form 'name=value'.
|
||||
|
||||
Bash provides several ways to manipulate the environment. On invocation, the
|
||||
shell scans its own environment and creates a parameter for each name found,
|
||||
automatically marking it for 'export' to child processes. Executed commands
|
||||
inherit the environment. The 'export' and 'unset' builtins allow parameters to
|
||||
be added to and deleted from the environment. If the value of a parameter in
|
||||
the environment is modified using the 'export' builtin, the new value becomes
|
||||
part of the environment, replacing the old. The environment inherited by any
|
||||
executed command consists of the shell's initial environment, whose values may
|
||||
be modified in the shell, less any pairs removed by the 'unset' builtin, plus
|
||||
any additions via the 'export' command.
|
||||
|
||||
#### Exit Status
|
||||
cf. 3.7.5 Exit Status
|
||||
|
||||
The exit status of an executed command is the value returned by the 'waitpid'
|
||||
system call or equivalent function. Exit statuses fall between 0 and 255,
|
||||
though, as explained below, the shell may use values above 125 specially. Exit
|
||||
statuses from shell builtins and compound commands are also limited to this
|
||||
range. Under certain circumstances, the shell will use special values to
|
||||
indicate specific failure modes.
|
||||
|
||||
For the shell's purposes, a command which exits with a zero exit status has
|
||||
succeeded. A non-zero exit status indicates failure. This seemingly
|
||||
counter-intuitive scheme is used so there is one well-defined way to indicate
|
||||
success and a variety of ways to indicate various failure modes. When a command
|
||||
terminates on a fatal signal whose number is N, Bash uses the value 128+N as the
|
||||
exit status.
|
||||
|
||||
If a command is not found, the child process created to execute it returns a
|
||||
status of 127. If a command is found but is not executable, the return status
|
||||
is 126.
|
||||
|
||||
If a command fails because of an error during expansion or redirection, the exit
|
||||
status is greater than zero.
|
||||
|
||||
All of the Bash builtins return an exit status of zero if they succeed and a
|
||||
non-zero status on failure, so they may be used by the conditional and list
|
||||
constructs. All builtins return an exit status of 2 to indicate incorrect
|
||||
usage, generally invalid options or missing arguments.
|
||||
|
||||
The exit status of the last command is available in the special parameter $?.
|
||||
|
||||
#### Signals
|
||||
cf. 3.7.6 Signals
|
||||
|
||||
When Bash is interactive, it ignores 'SIGTERM' (so that 'kill 0' does not kill
|
||||
an interactive shell), and 'SIGINT' is caught and handled. When Bash receives a
|
||||
'SIGINT', it breaks out of any executing loops. In all cases, Bash ignores
|
||||
'SIGQUIT'. Bash ignores 'SIGTTIN', 'SIGTTOU', and 'SIGTSTP'.
|
||||
|
||||
NOTE: The behaviour on when ^C is printed seems strange, investigate further
|
||||
once we implement this
|
||||
|
||||
TODO: investigate this further, this seems very complicated
|
||||
|
||||
## Definitions
|
||||
cf. [Bash Reference Manual](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Definitions)
|
||||
cf. 2 Definitions
|
||||
|
||||
**token**
|
||||
A sequence of characters considered a single unit by the shell. It is either a
|
||||
word or an operator
|
||||
|
||||
**word**
|
||||
A sequence of characters treated as a unit by the shell. Words may not include
|
||||
unquoted metacharacters.
|
||||
|
||||
**operator**
|
||||
A **control operator** or a **redirection operator**.
|
||||
Operators contain at least one unquoted **metacharacter**.
|
||||
|
||||
**control operator**
|
||||
A token that performs a control function.
|
||||
|
||||
It is a newline or one of the following: '|', ‘||’, ‘&&’, ‘(’, or ‘)’.
|
||||
|
||||
**redirection operator**
|
||||
For our project:
|
||||
|
||||
'<' redirects input
|
||||
|
||||
'>' redirects output
|
||||
|
||||
'<<' is here_doc with delimiter.
|
||||
delimiter is a **word**.
|
||||
Does not have to update history
|
||||
|
||||
'>>' redirects output in append mode
|
||||
|
||||
**blank**
|
||||
A space or tab character
|
||||
BIN
fuzz_hand_tester
BIN
fuzz_hand_tester
Binary file not shown.
|
|
@ -13,7 +13,7 @@ PIPELINE -> PIPELINE | GROUP_OR_SIMPLE
|
|||
PIPELINE -> GROUP_OR_SIMPLE
|
||||
GROUP_OR_SIMPLE -> (CMDS) REDIR
|
||||
GROUP_OR_SIMPLE -> SIMPLE
|
||||
SIMPLE -> REDIR word REDIR SIMPLE_LST
|
||||
SIMPLE -> REDIR SIMPLE_LST
|
||||
SIMPLE_LST -> word REDIR SIMPLE_LST
|
||||
SIMPLE_LST -> ε
|
||||
REDIR -> > word REDIR
|
||||
|
|
@ -41,9 +41,9 @@ OPT_PIPELINE -> | GROUP_OR_SIMPLE OPT_PIPELINE
|
|||
OPT_PIPELINE -> ε
|
||||
GROUP_OR_SIMPLE -> (CMDS) REDIR
|
||||
GROUP_OR_SIMPLE -> SIMPLE
|
||||
SIMPLE -> REDIR SIMPLE_TAIL
|
||||
SIMPLE_TAIL -> word REDIR SIMPLE_TAIL
|
||||
SIMPLE_TAIL -> ε
|
||||
SIMPLE -> REDIR SIMPLE_LST
|
||||
SIMPLE_LST -> word REDIR SIMPLE_LST
|
||||
SIMPLE_LST -> ε
|
||||
REDIR -> > word REDIR
|
||||
REDIR -> >> word REDIR
|
||||
REDIR -> < word REDIR
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
jguelen@c2r12p1 ~()% bash
|
||||
jguelen@c2r12p1:~$ export test=flagada$PATH
|
||||
jguelen@c2r12p1:~$ echo $test
|
||||
flagada/home/jguelen/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin
|
||||
jguelen@c2r12p1:~$ export test="flagada"$PATH
|
||||
jguelen@c2r12p1:~$ echo $test
|
||||
flagada/home/jguelen/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin
|
||||
jguelen@c2r12p1:~$ export test=flagada"$PATHhihi"
|
||||
jguelen@c2r12p1:~$ echo $test
|
||||
flagada
|
||||
jguelen@c2r12p1:~$ export test=flagada"$PATH hihi"
|
||||
jguelen@c2r12p1:~$ echo $test
|
||||
flagada/home/jguelen/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin hihi
|
||||
jguelen@c2r12p1:~$ export test=flagada"$PATH"hihi
|
||||
jguelen@c2r12p1:~$ echo $test
|
||||
flagada/home/jguelen/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/binhihi
|
||||
jguelen@c2r12p1:~$ export test=flagada"$'PA'TH"hihi
|
||||
jguelen@c2r12p1:~$ echo $test
|
||||
flagada$'PA'THhihi
|
||||
jguelen@c2r12p1:~$ export test=flagada$'P'ATH
|
||||
jguelen@c2r12p1:~$ echo $test
|
||||
flagadaPATH
|
||||
jguelen@c2r12p1:~$ export test=flagada$P'A'TH hihi
|
||||
jguelen@c2r12p1:~$ echo $test
|
||||
flagadaATH
|
||||
jguelen@c2r12p1:~/Common_Core/minishell$ echo "tests$"PATH""
|
||||
tests$PATH
|
||||
jguelen@c2r12p1:~$
|
||||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* buffer.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/12/12 12:39:58 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/09 17:26:24 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:44:10 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -39,12 +39,6 @@ void ft_buffer_free(t_buffer *buffer)
|
|||
free(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
** grows the buffer such that the new capacity is 1.5 times the old.
|
||||
**
|
||||
** in case of error, free all memory and return null.
|
||||
** else return buffer.
|
||||
*/
|
||||
t_buffer *ft_buffer_grow(t_buffer *buffer)
|
||||
{
|
||||
char *newbuffer;
|
||||
|
|
@ -81,15 +75,6 @@ t_buffer *ft_buffer_pushchar(t_buffer *buffer, char c)
|
|||
return (buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
** push buf to the end of buffer, growing buffer if needed.
|
||||
**
|
||||
** also adds an additional null byte to terminate the buffer.
|
||||
**
|
||||
** the number of bytes to copy to buffer is n.
|
||||
** returns buffer.
|
||||
** in case of error, all memory is freed and null is returned.
|
||||
*/
|
||||
t_buffer *ft_buffer_push_buf(t_buffer *buffer, char *buf, size_t n)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
|
|
|
|||
|
|
@ -3,22 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* buffer_charptr.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/10 18:45:49 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/10 18:46:35 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:43:47 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "buffer.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** Free this buffer, but return a pointer to the internal string, which is not
|
||||
** freed.
|
||||
**
|
||||
** If buffer is null, return null.
|
||||
*/
|
||||
char *ft_buffer_to_charptr(t_buffer *buffer)
|
||||
{
|
||||
char *out;
|
||||
|
|
|
|||
13
src/env/env.c
vendored
13
src/env/env.c
vendored
|
|
@ -3,19 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* env.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 13:59:20 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/19 14:42:35 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:39:37 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "env.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** Free the given env node.
|
||||
*/
|
||||
void env_destroy_node(t_env *env)
|
||||
{
|
||||
if (!env)
|
||||
|
|
@ -25,9 +22,6 @@ void env_destroy_node(t_env *env)
|
|||
free(env);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the given env linked list.
|
||||
*/
|
||||
void env_destroy(t_env *env)
|
||||
{
|
||||
t_env *next;
|
||||
|
|
@ -42,9 +36,6 @@ void env_destroy(t_env *env)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Get the number of mappings in the givne env linked list
|
||||
*/
|
||||
size_t env_get_size(t_env *env)
|
||||
{
|
||||
size_t nb_elem;
|
||||
|
|
|
|||
22
src/env/env_convert.c
vendored
22
src/env/env_convert.c
vendored
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* env_convert.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 14:39:57 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/19 16:41:08 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:44:33 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -15,13 +15,6 @@
|
|||
#include "envp.h"
|
||||
#include "libft.h"
|
||||
|
||||
/*
|
||||
** Create an envp structure from the given env linked list.
|
||||
**
|
||||
** The linked list is not destroyed.
|
||||
**
|
||||
** in case of allocation error, all memory is freed and NULL is returned.
|
||||
*/
|
||||
char **envp_from_env(t_env *env)
|
||||
{
|
||||
char **new_envp;
|
||||
|
|
@ -48,17 +41,6 @@ char **envp_from_env(t_env *env)
|
|||
return (new_envp);
|
||||
}
|
||||
|
||||
/*
|
||||
** read an envp structure, and create a t_env linked list containing the same
|
||||
** information.
|
||||
**
|
||||
** the envp structure is not freed.
|
||||
**
|
||||
** in case of error, all memory is freed and null is returned.
|
||||
**
|
||||
** no checks additional checks than those of envp_get_key and envp_get_val are
|
||||
** performed
|
||||
*/
|
||||
t_env *env_from_envp(char **envp)
|
||||
{
|
||||
t_env *env;
|
||||
|
|
|
|||
61
src/env/env_manip.c
vendored
61
src/env/env_manip.c
vendored
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/19 17:55:24 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/21 18:49:56 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:45:01 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,11 +16,6 @@
|
|||
#include "libft.h"
|
||||
#include "../ft_errno.h"
|
||||
|
||||
/*
|
||||
** Get the value corresponding to a given key in the given environment structure
|
||||
**
|
||||
** If not found, return null
|
||||
*/
|
||||
char *env_get_val(t_env *env, char *key)
|
||||
{
|
||||
t_env *node;
|
||||
|
|
@ -31,17 +26,6 @@ char *env_get_val(t_env *env, char *key)
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove the first env node of the given linked list where the key matches the
|
||||
** given key.
|
||||
**
|
||||
** In any given env linked list, there should only be one entry for a given key.
|
||||
**
|
||||
** If the linked list is empty or the pointer is NULL, nothing is done.
|
||||
**
|
||||
** If the linked list does not contain an element matching the given key,
|
||||
** nothing is done.
|
||||
*/
|
||||
void env_rm_entry(t_env **env, char *key)
|
||||
{
|
||||
t_env *current;
|
||||
|
|
@ -70,9 +54,6 @@ void env_rm_entry(t_env **env, char *key)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the given element to the end of the given linked list.
|
||||
*/
|
||||
static void env_add_back(t_env **env, t_env *new)
|
||||
{
|
||||
t_env *last;
|
||||
|
|
@ -88,37 +69,6 @@ static void env_add_back(t_env **env, t_env *new)
|
|||
last->next = new;
|
||||
}
|
||||
|
||||
/*
|
||||
** In the given env linked list, if an element with the given key exist, set its
|
||||
** value to the one provided. If no such element exist, create a new one with
|
||||
** the provided value.
|
||||
**
|
||||
** The provided key and value must be allocated. In case of error, they will be
|
||||
** freed. In case a node matching the given key is found the provided key value
|
||||
** is freed.
|
||||
**
|
||||
** If key or value is null, both key and value are freed and NULL is returned.
|
||||
** ft_errno is set to FT_EINVAL. We therefore allow for a value to be NULL.
|
||||
**
|
||||
** If key is an empty string, key and value are freed, ft_errno is set to
|
||||
** FT_EBADID, and NULL is returned.
|
||||
**
|
||||
** If there is a failure allocating a new node, NULL is returned and ft_errno is
|
||||
** set to FT_EERRNO (malloc would have set it to ENOMEM).
|
||||
**
|
||||
** Returns a pointer to the first element in the linked list, or NULL on error.
|
||||
**
|
||||
** Warning: does not check for validity of a key beyond what is described above.
|
||||
**
|
||||
** Implementation notes: free2 always returns NULL
|
||||
**
|
||||
** Note: once you pass a key to this function, if you pass it a second time, it
|
||||
** will cause bad behaviour.
|
||||
**
|
||||
** Once you passed key and/or value to this function, env is the owner of these
|
||||
** values and is responsible for freeing them. Do not pass multiple times the
|
||||
** same pointers to this function!
|
||||
*/
|
||||
t_env *env_set_entry(t_env **env, char *key, char *value)
|
||||
{
|
||||
t_env *node;
|
||||
|
|
@ -146,15 +96,6 @@ t_env *env_set_entry(t_env **env, char *key, char *value)
|
|||
return (*env);
|
||||
}
|
||||
|
||||
/*
|
||||
** Find and return a pointer to the node in the given env linked list where the
|
||||
** key matches the given key.
|
||||
**
|
||||
** If the node is not found, return NULL.
|
||||
**
|
||||
** Note that this is a pointer to the middle of the linked list, the node is not
|
||||
** copied.
|
||||
*/
|
||||
t_env *env_find_node_bykey(t_env *env, char *key)
|
||||
{
|
||||
while (env)
|
||||
|
|
|
|||
31
src/env/envp.c
vendored
31
src/env/envp.c
vendored
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* envp.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 13:35:44 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/19 13:43:19 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:40:06 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -14,18 +14,6 @@
|
|||
#include "libft.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
** Get the key part of a line of envp
|
||||
**
|
||||
** given that line is of the form key=value, return a string containing key,
|
||||
** which is allocated and must be freed.
|
||||
**
|
||||
** if line is null or is empty, return NULL
|
||||
**
|
||||
** if line contains no '=', return an copy of line
|
||||
**
|
||||
** if allocation fail, return NULL
|
||||
*/
|
||||
char *envp_get_key(char *line)
|
||||
{
|
||||
char *key;
|
||||
|
|
@ -44,18 +32,6 @@ char *envp_get_key(char *line)
|
|||
return (key);
|
||||
}
|
||||
|
||||
/*
|
||||
** Get the value part of a line of envp
|
||||
**
|
||||
** given that line is of the form key=value, return a string containing value,
|
||||
** which is allocated and must be freed.
|
||||
**
|
||||
** if line is null or is empty, return NULL
|
||||
**
|
||||
** if line contains no '=', return an empty string
|
||||
**
|
||||
** if allocation fail, return NULL
|
||||
*/
|
||||
char *envp_get_val(char *line)
|
||||
{
|
||||
char *val_pointer;
|
||||
|
|
@ -69,9 +45,6 @@ char *envp_get_val(char *line)
|
|||
return (ft_strdup(val_pointer));
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all memory related to a given envp structure
|
||||
*/
|
||||
void envp_destroy(char **envp)
|
||||
{
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/04 19:55:22 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/28 12:29:50 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:19:51 by kcolin ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -29,9 +29,5 @@ void do_waitpid(t_minishell *app, int pid)
|
|||
if (WIFEXITED(wstatus))
|
||||
app->last_return_value = WEXITSTATUS(wstatus);
|
||||
if (WIFSIGNALED(wstatus))
|
||||
{
|
||||
app->last_return_value = 128 + WTERMSIG(wstatus);
|
||||
if (WTERMSIG(wstatus) == SIGQUIT)
|
||||
ft_dprintf(STDERR_FILENO, "Quit (core dumped)");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* connec_pipe_cmd_execute.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/11 12:01:29 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/30 11:49:59 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:46:28 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -38,8 +38,8 @@ static void fork_failure(t_minishell *app, int pipefd[2])
|
|||
}
|
||||
|
||||
/*
|
||||
** return the pid returned by fork. values greater than 0 indicate parentprocess
|
||||
*/
|
||||
** return the pid returned by fork.
|
||||
*/
|
||||
static int exec_pid1(t_minishell *app, int pipefd[2], t_cmd *cmd)
|
||||
{
|
||||
int pid1;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* here_doc.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/07 11:42:29 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/29 16:56:08 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:47:33 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -22,19 +22,6 @@
|
|||
char *expand_line(char *line, t_minishell *app);
|
||||
void failed_to_open_tmp_file(void);
|
||||
|
||||
/*
|
||||
** Read from infd into some file until a line that is exactly equal to the
|
||||
** marker is read.
|
||||
**
|
||||
** Then unlink the file, and return a filedescriptor to it, seeked to the start.
|
||||
**
|
||||
** If the marker is not quoted, perform variable expansion on each line. If app
|
||||
** is NULL, no variable expansions are performed.
|
||||
**
|
||||
** If NULL is given as argument, or marker->word is null, or infd is negative,
|
||||
** or getting a random filename fails, or we are unable to create the file, or
|
||||
** the file already exists, or any other error occurs, return NULL.
|
||||
*/
|
||||
char *here_doc(t_worddesc *marker, int infd, t_minishell *app)
|
||||
{
|
||||
int outfd;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/17 11:50:08 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/29 16:39:22 by kcolin ### ########.fr */
|
||||
/* Created: 2025/05/02 14:36:33 by kcolin #+# #+# */
|
||||
/* Updated: 2025/05/02 14:36:33 by kcolin ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,13 +16,6 @@
|
|||
#include "here_doc.h"
|
||||
#include "../../sig/sig.h"
|
||||
|
||||
/*
|
||||
** - check that arguments are not invalid
|
||||
** - create a random filename
|
||||
** - create the file
|
||||
**
|
||||
** do these operations, with error checking
|
||||
*/
|
||||
int setup_here_doc(t_worddesc *marker, int infd, char **filename)
|
||||
{
|
||||
int outfd;
|
||||
|
|
@ -38,9 +31,6 @@ int setup_here_doc(t_worddesc *marker, int infd, char **filename)
|
|||
return (outfd);
|
||||
}
|
||||
|
||||
/*
|
||||
** output line to outfd, get the next line from infd, and return it
|
||||
*/
|
||||
char *output_line_and_next(int infd, int outfd, char *line)
|
||||
{
|
||||
ft_dprintf(outfd, "%s", line);
|
||||
|
|
@ -49,9 +39,6 @@ char *output_line_and_next(int infd, int outfd, char *line)
|
|||
return (line);
|
||||
}
|
||||
|
||||
/*
|
||||
** closes outfd, reset correct sig mode handling
|
||||
*/
|
||||
char *finalize(int outfd, char *filename)
|
||||
{
|
||||
close(outfd);
|
||||
|
|
@ -61,7 +48,6 @@ char *finalize(int outfd, char *filename)
|
|||
|
||||
int interupted(int outfd, char *filename)
|
||||
{
|
||||
ft_printf("\n");
|
||||
close(outfd);
|
||||
unlink(filename);
|
||||
free(filename);
|
||||
|
|
@ -70,11 +56,6 @@ int interupted(int outfd, char *filename)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
** check if line corresponds to marker
|
||||
**
|
||||
** if true is returned, line has been freed
|
||||
*/
|
||||
bool is_marker(char *line, t_worddesc *marker)
|
||||
{
|
||||
char *cleanline;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* random_filename.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/11 13:29:32 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/11 13:30:33 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:48:11 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -17,17 +17,6 @@
|
|||
#include <unistd.h>
|
||||
#include "libft.h"
|
||||
|
||||
/*
|
||||
** Genereate a random filename for use by here_doc
|
||||
**
|
||||
** The filename will be of the form
|
||||
** /tmp/minishell_here_doc_XXXXXXXXXXX
|
||||
** where each X is a random alphanumerical char
|
||||
**
|
||||
** Random bytes are generated by reading from /dev/urandom
|
||||
**
|
||||
** Return NULL and sets ft_errno on error
|
||||
*/
|
||||
char *here_doc_random_filename(void)
|
||||
{
|
||||
int randomfd;
|
||||
|
|
|
|||
|
|
@ -3,20 +3,15 @@
|
|||
/* ::: :::::::: */
|
||||
/* strip_newline.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/11 13:31:22 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/11 13:31:31 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:48:08 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "libft.h"
|
||||
|
||||
/*
|
||||
** create a new string without the terminating newline of the given string.
|
||||
**
|
||||
** If the given string has no terminating newline, create a copy of the input
|
||||
*/
|
||||
char *strip_newline(char *str)
|
||||
{
|
||||
size_t last_char_idx;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* simple_cmd_execute.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/27 16:21:56 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/30 15:08:01 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:49:22 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -49,9 +49,6 @@ static void command_not_found(t_simple_cmd *cmd, t_minishell *app)
|
|||
app->last_return_value = 127;
|
||||
}
|
||||
|
||||
/*
|
||||
** Do all the post-processing steps relating to a command.
|
||||
*/
|
||||
static t_simple_cmd *post_process_command(t_simple_cmd *cmd, t_minishell *app)
|
||||
{
|
||||
simple_cmd_post_process_debug(cmd, app);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/21 12:40:46 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/24 16:49:17 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:09:45 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -15,13 +15,6 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
** get or set ft_errno
|
||||
**
|
||||
** if errno is FT_EGET, return ft_errno and do not set it
|
||||
**
|
||||
** else set ft_errno to errno, and return the previous value of ft_errno
|
||||
*/
|
||||
t_errno ft_errno(t_errno errno)
|
||||
{
|
||||
static t_errno ft_errno = FT_ESUCCESS;
|
||||
|
|
@ -36,9 +29,6 @@ t_errno ft_errno(t_errno errno)
|
|||
return (ft_errno);
|
||||
}
|
||||
|
||||
/*
|
||||
** get the current value of ft_errno
|
||||
*/
|
||||
t_errno ft_errno_get(void)
|
||||
{
|
||||
return (ft_errno(FT_EGET));
|
||||
|
|
|
|||
39
src/fuzz.c
39
src/fuzz.c
|
|
@ -1,39 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* fuzz.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/30 16:01:18 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/30 17:13:17 by kcolin ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "fcntl.h"
|
||||
#include "minishell.h"
|
||||
#include "parser/cmd/cmd_destroy.h"
|
||||
#include "parser/cmd_parsing.h"
|
||||
#include "unistd.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
t_minishell app;
|
||||
bzero(&app, sizeof(t_minishell));
|
||||
int null = open("/dev/null", O_RDONLY, 0);
|
||||
|
||||
char *line = (char *)calloc(size + 1, sizeof(char));
|
||||
memcpy(line, data, size);
|
||||
|
||||
dup2(null, STDIN_FILENO);
|
||||
close(null);
|
||||
t_cmd *cmd = minishell_parse(&app, line);
|
||||
|
||||
cmd_destroy(cmd);
|
||||
free(line);
|
||||
|
||||
return (0); // Values other than 0 and -1 are reserved for future use.
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* fuzz_hand_tester.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/30 17:30:53 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/30 17:36:33 by kcolin ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "fcntl.h"
|
||||
#include "minishell.h"
|
||||
#include "parser/cmd/cmd_destroy.h"
|
||||
#include "parser/cmd_parsing.h"
|
||||
#include "unistd.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
t_minishell app;
|
||||
bzero(&app, sizeof(t_minishell));
|
||||
int null = open("/dev/null", O_RDONLY, 0);
|
||||
|
||||
if (argc != 2)
|
||||
return (1);
|
||||
FILE *in = fopen(argv[1], "rb");
|
||||
fseek(in, 0, SEEK_END);
|
||||
long fsize = ftell(in);
|
||||
fseek(in, 0, SEEK_SET); /* same as rewind(f); */
|
||||
char *line = malloc(fsize + 1);
|
||||
fread(line, fsize, 1, in);
|
||||
fclose(in);
|
||||
line[fsize] = 0;
|
||||
|
||||
|
||||
dup2(null, STDIN_FILENO);
|
||||
close(null);
|
||||
t_cmd *cmd = minishell_parse(&app, line);
|
||||
|
||||
cmd_destroy(cmd);
|
||||
free(line);
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* get_command.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 18:03:11 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/29 15:04:59 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:10:04 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -20,9 +20,6 @@
|
|||
#include "libft.h"
|
||||
#include "get_command.h"
|
||||
|
||||
/*
|
||||
** remove one '\n' from the end of the string, if it exists
|
||||
*/
|
||||
static char *strip_newline(char *str)
|
||||
{
|
||||
size_t last_char_idx;
|
||||
|
|
@ -54,14 +51,6 @@ static char *handle_special_command(char *line, t_minishell *app)
|
|||
return (line);
|
||||
}
|
||||
|
||||
/*
|
||||
** get a command line using readline.
|
||||
**
|
||||
** returned buffer must be freed by caller.
|
||||
** will add command to history if appropriate.
|
||||
**
|
||||
** Also handles special commands, which are not further processed.
|
||||
*/
|
||||
char *get_command(t_minishell *app)
|
||||
{
|
||||
char *line;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* minishell.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/29 15:13/45 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/29 15:13:45 by kcolin ### ########.fr */
|
||||
/* Created: 2025/05/02 11:53:53 by kcolin #+# #+# */
|
||||
/* Updated: 2025/05/02 13:10:24 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -24,11 +24,9 @@
|
|||
#include "postprocess/fieldsplit/fieldsplit.h"
|
||||
#include "postprocess/expansion/expand_wildcard.h"
|
||||
#include "sig/sig.h"
|
||||
#include "sig/sig_handlers.h"
|
||||
#include "parser/cmd/cmd_debug.h"
|
||||
|
||||
/*
|
||||
** execute command
|
||||
*/
|
||||
static t_subprocess execute_command(t_cmd *cmd, t_minishell *app)
|
||||
{
|
||||
int retvalue;
|
||||
|
|
@ -49,24 +47,6 @@ static void debug_command(t_cmd *cmd, t_minishell *app)
|
|||
cmd_root_debug(cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
** Do all the post-processing steps relating to a simple command.
|
||||
*/
|
||||
/* static t_simple_cmd
|
||||
* *post_process_command(t_simple_cmd *cmd, t_minishell *app) */
|
||||
/* { */
|
||||
/* if (simple_cmd_expand_vars(cmd, app) == NULL) */
|
||||
/* return (simple_cmd_destroy(cmd), NULL); */
|
||||
/* if (simple_cmd_fieldsplit(cmd) == NULL) */
|
||||
/* return (simple_cmd_destroy(cmd), NULL); */
|
||||
/* if (simple_cmd_expand_wildcards(cmd) == NULL) */
|
||||
/* return (simple_cmd_destroy(cmd), NULL); */
|
||||
/* return (cmd); */
|
||||
/* } */
|
||||
|
||||
/*
|
||||
** Initialize main app structure
|
||||
*/
|
||||
static void app_init(t_minishell *app, char **envp)
|
||||
{
|
||||
ft_bzero(app, sizeof(t_minishell));
|
||||
|
|
@ -88,6 +68,8 @@ int main(int argc, char *argv[], char **envp)
|
|||
line = get_command(&app);
|
||||
while (line != NULL)
|
||||
{
|
||||
if (g_signum != 0)
|
||||
app.last_return_value = get_sig_retvalue();
|
||||
cmd = minishell_parse(&app, line);
|
||||
free(line);
|
||||
debug_command(cmd, &app);
|
||||
|
|
@ -95,8 +77,6 @@ int main(int argc, char *argv[], char **envp)
|
|||
cmd_destroy(cmd);
|
||||
if (retvalue == SUBPROCESS)
|
||||
break ;
|
||||
if (g_signum != 0)
|
||||
readline_reset();
|
||||
line = get_command(&app);
|
||||
}
|
||||
env_destroy(app.env);
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* minishell.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/09 14:02:47 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/30 11:28:11 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:11:18 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -56,7 +56,6 @@ typedef struct s_redirect
|
|||
int open_flags;
|
||||
int c_flags; // flags for third arg of open (case O_CREAT).
|
||||
t_redirectee redirectee; // fd or filename where to redirect source.
|
||||
// used between var expansion and fieldsplit
|
||||
char *unexpanded_filename;
|
||||
char *here_doc_eof; // The here-document limiter if relevant.
|
||||
} t_redirect;
|
||||
|
|
@ -74,13 +73,7 @@ typedef enum e_cmd_type
|
|||
typedef struct s_cmd
|
||||
{
|
||||
t_cmd_type type;
|
||||
/*
|
||||
** flags will probably be useless to us for now.
|
||||
*/
|
||||
int flags;
|
||||
/*
|
||||
** Line number the command starts on -> will probably be unused.
|
||||
*/
|
||||
int line;
|
||||
union u_value
|
||||
{
|
||||
|
|
@ -98,10 +91,6 @@ typedef enum e_connector
|
|||
FT_OR,
|
||||
} t_connector;
|
||||
|
||||
/*
|
||||
** This exists to represent pipelines and AND or OR lists.
|
||||
** does include left associativity.
|
||||
*/
|
||||
typedef struct s_connec_cmd
|
||||
{
|
||||
t_cmd *first;
|
||||
|
|
@ -109,12 +98,6 @@ typedef struct s_connec_cmd
|
|||
t_connector connector;
|
||||
} t_connec_cmd;
|
||||
|
||||
/*
|
||||
** We do not deal with { list; } grouping. This is therefore roughly
|
||||
** equivalent to a subshell_com structure in bash. And therefore we
|
||||
** define this only since it will still be a grouping regarding redirections
|
||||
** AND require a subshell every time in the case of minishell.
|
||||
*/
|
||||
typedef struct s_group_cmd
|
||||
{
|
||||
t_cmd *cmd;
|
||||
|
|
@ -123,7 +106,7 @@ typedef struct s_group_cmd
|
|||
|
||||
typedef struct s_simple_cmd
|
||||
{
|
||||
int line; //Probably unused.
|
||||
int line;
|
||||
t_wordlist *words; //argv in list form
|
||||
t_redirect *redirections; //redirections to perform
|
||||
} t_simple_cmd;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/09 16:53:02 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/30 18:00:28 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 14:35:54 by kcolin ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -23,7 +23,8 @@ void redirect_destroy(t_redirect *redirect)
|
|||
{
|
||||
next = redirect->next;
|
||||
free(redirect->here_doc_eof);
|
||||
if (redirect->type == FT_HEREDOC)
|
||||
if (redirect->type == FT_HEREDOC && redirect->redirectee.filename != NULL
|
||||
&& redirect->redirectee.filename->word != NULL)
|
||||
unlink(redirect->redirectee.filename->word);
|
||||
worddesc_destroy(redirect->redirectee.filename);
|
||||
free(redirect->unexpanded_filename);
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* cmds_parse.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/16 13:11:33 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/16 13:12:15 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:49:54 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -17,9 +17,6 @@
|
|||
#include "cmd_destroy.h"
|
||||
#include "../connec_cmd/connec_reorient_subtree.h"
|
||||
|
||||
/*
|
||||
** Parse list of commands or pipeline.
|
||||
*/
|
||||
t_cmd *minishell_cmds_parse(t_minishell *app, t_wordlist **tokens)
|
||||
{
|
||||
t_cmd *subtree;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* cmd_parsing.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/31 10:28:28 by jguelen #+# #+# */
|
||||
/* Updated: 2025/04/25 13:17:56 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:00:27 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -50,9 +50,6 @@ static t_cmd *expecting_quote_error(t_minishell *app)
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** TODO check if we need to differentiate the cause of a NULL return.
|
||||
*/
|
||||
t_cmd *minishell_parse(t_minishell *app, char *command_line)
|
||||
{
|
||||
t_cmd *root_cmd;
|
||||
|
|
|
|||
|
|
@ -3,23 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* identifier.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 14:43:57 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/19 14:47:00 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:50:55 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "identifier.h"
|
||||
#include "libft.h"
|
||||
|
||||
/*
|
||||
** Return true if id is a valid bash identifier, false otherwise.
|
||||
**
|
||||
** A valid identifier starts with one of a-zA-Z_
|
||||
** It can contain any char a-zA-Z0-9_
|
||||
** It must contain at least one char
|
||||
*/
|
||||
bool is_identifier(char *id)
|
||||
{
|
||||
if (id == NULL || id[0] == '\0')
|
||||
|
|
|
|||
|
|
@ -3,23 +3,15 @@
|
|||
/* ::: :::::::: */
|
||||
/* metacharacter.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/06 15:23:31 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/11 19:04:03 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:51:07 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "metacharacter.h"
|
||||
|
||||
// FIXME: use ft_strchr
|
||||
/*
|
||||
** return true if the character is a metacharacter
|
||||
**
|
||||
** Bash reference manual: A character that, when unquoted, separates words. A
|
||||
** metacharacter is a space, tab, newline, or one of the following characters:
|
||||
** ‘|’, ‘&’, ‘(’, ‘)’, ‘<’, or ‘>’.
|
||||
*/
|
||||
bool is_metacharacter(char c)
|
||||
{
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '|' || c == '&'
|
||||
|
|
|
|||
|
|
@ -3,25 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* operator_combo.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/17 16:30:54 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/17 16:34:34 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:51:16 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "libft.h"
|
||||
|
||||
/*
|
||||
** return true if c can be used as the next character for an operator in start
|
||||
**
|
||||
** recognized operators are:
|
||||
** ||
|
||||
** >>
|
||||
** <<
|
||||
** &&
|
||||
*/
|
||||
bool is_operator_combo(char *start, char c)
|
||||
{
|
||||
if (ft_strlen(start) != 1)
|
||||
|
|
|
|||
|
|
@ -3,19 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* operator_start.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/17 16:21:03 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/18 17:53:13 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:51:23 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "libft.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
** Is the character the start of an operator?
|
||||
*/
|
||||
bool is_operator_start(char c)
|
||||
{
|
||||
if (ft_strchr("<>|&()", c) != NULL)
|
||||
|
|
|
|||
|
|
@ -3,19 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* pipe.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/21 15:04:48 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/21 15:06:00 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:51:30 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "pipe.h"
|
||||
#include "libft.h"
|
||||
|
||||
/*
|
||||
** return true if the given worddesc is a pipe operator "|"
|
||||
*/
|
||||
bool is_pipe(t_worddesc *word)
|
||||
{
|
||||
if (ft_strcmp("|", word->word) == 0)
|
||||
|
|
|
|||
|
|
@ -3,18 +3,15 @@
|
|||
/* ::: :::::::: */
|
||||
/* quote.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/20 13:21:08 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/20 13:22:12 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:51:44 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "quote.h"
|
||||
|
||||
/*
|
||||
** return true if c is either ' or "
|
||||
*/
|
||||
bool is_quote(char c)
|
||||
{
|
||||
if (c == '\'' || c == '"')
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/30 10:35/43 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/30 10:35:43 by kcolin ### ########.fr */
|
||||
/* Created: 2025/05/02 14:40:34 by kcolin #+# #+# */
|
||||
/* Updated: 2025/05/02 14:40:34 by kcolin ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ t_redirect *redir_from_words(t_worddesc *operator,
|
|||
here_doc(spec, STDIN_FILENO, app), 0, NULL, WORD_TOKEN);
|
||||
worddesc_destroy(spec);
|
||||
if (redir->redirectee.filename == NULL)
|
||||
return (redirect_destroy(redir), ft_errno(FT_EERRNO), NULL);
|
||||
return (redirect_destroy(redir), NULL);
|
||||
}
|
||||
else
|
||||
redir->redirectee.filename = specifier;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* redirect_from_words.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/14 17:31:23 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/14 17:32:12 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:52:22 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/20 17:36:20 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/28 16:43:53 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:53:03 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -44,9 +44,6 @@ static t_redirect *redirection_remove_quotes(t_redirect *in_list)
|
|||
return (out_list);
|
||||
}
|
||||
|
||||
/*
|
||||
** do quote removal on all words of this simple cmd
|
||||
*/
|
||||
t_simple_cmd *simple_cmd_remove_quotes(t_simple_cmd *cmd)
|
||||
{
|
||||
t_wordlist *new;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* remove_quotes.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/15 12:00/08 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/15 12:00:08 by kcolin ### ########.fr */
|
||||
/* Created: 2025/04/15 12:00:08 by kcolin #+# #+# */
|
||||
/* Updated: 2025/05/02 12:53:14 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -22,16 +22,6 @@ static bool is_ignore_mark(char c)
|
|||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
** use the marker in the given worddesc to create a new worddesc by removing
|
||||
** unquoted quotes.
|
||||
**
|
||||
** The new worddesc will have the marker set to NULL.
|
||||
**
|
||||
** If word is null return null.
|
||||
**
|
||||
** In case of allocation failure, return null
|
||||
*/
|
||||
t_worddesc *remove_quotes(t_worddesc *word)
|
||||
{
|
||||
t_worddesc *output;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* simple_cmd.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/21 12:30:07 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/29 13:09:43 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:53:31 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,11 +16,6 @@
|
|||
#include "../redirect/redirect_debug.h"
|
||||
#include "../cmd/cmd_destroy.h"
|
||||
|
||||
/*
|
||||
** parse a wordlist and yield a simple command.
|
||||
**
|
||||
** takes ownership of words
|
||||
*/
|
||||
t_simple_cmd *simple_cmd_from_wordlist(t_wordlist *words)
|
||||
{
|
||||
t_simple_cmd *cmd;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* worddesc.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/13 17:20:36 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/18 09:20:14 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:54:18 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -14,17 +14,6 @@
|
|||
#include "libft.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** allocate a new worddesc with given flags, marker, and word.
|
||||
**
|
||||
** mark_string is initialized as a string of the same length as word, but filled
|
||||
** with spaces
|
||||
**
|
||||
** return null in case of error, or if word is null
|
||||
**
|
||||
** In case of allocation error, word is freed, as well as any memory allocated
|
||||
** in this function
|
||||
*/
|
||||
t_worddesc *worddesc_create(char *word, char flags, char *marker,
|
||||
t_token_type type)
|
||||
{
|
||||
|
|
@ -42,9 +31,6 @@ t_worddesc *worddesc_create(char *word, char flags, char *marker,
|
|||
return (retvalue);
|
||||
}
|
||||
|
||||
/*
|
||||
** free all memory associated with this worddesc
|
||||
*/
|
||||
void worddesc_destroy(t_worddesc *worddesc)
|
||||
{
|
||||
if (worddesc == NULL)
|
||||
|
|
@ -54,9 +40,6 @@ void worddesc_destroy(t_worddesc *worddesc)
|
|||
free(worddesc);
|
||||
}
|
||||
|
||||
// copy the given worddesc, including all internal data
|
||||
//
|
||||
// return null on error
|
||||
t_worddesc *worddesc_copy(t_worddesc *worddesc)
|
||||
{
|
||||
t_worddesc *out;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* worddesc.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/15 12:00:08 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/17 14:30:48 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:54:56 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -49,27 +49,8 @@ typedef enum e_token_type
|
|||
*/
|
||||
typedef struct s_worddesc
|
||||
{
|
||||
/*
|
||||
** The word itself
|
||||
*/
|
||||
char *word;
|
||||
/*
|
||||
** flags for this word
|
||||
**s_worddesc
|
||||
** See above for flag definitions
|
||||
*/
|
||||
char flags;
|
||||
/*
|
||||
** a character mask for word to designate the status
|
||||
** of its characters and wether or not they are subject to modifications
|
||||
**
|
||||
** Possible flags are ''', '"', '$', '&', ' '
|
||||
**
|
||||
** ' ' the default, no flag, no meaning
|
||||
** ''' corresponding character is single-quoted
|
||||
** '"' corresponding character is double-quoted
|
||||
** '$' corresponding character is a result of $var expansion
|
||||
*/
|
||||
char *marker;
|
||||
t_token_type token_type;
|
||||
} t_worddesc;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/13 17:07:01 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/07 17:40:30 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:57:29 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -15,12 +15,6 @@
|
|||
#include "unistd.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** create a new wordlist element, with next set to null and word set to the
|
||||
** passed worddesc.
|
||||
**
|
||||
** in case of error, return null
|
||||
*/
|
||||
t_wordlist *wordlist_create(t_worddesc *word)
|
||||
{
|
||||
t_wordlist *retvalue;
|
||||
|
|
@ -33,9 +27,6 @@ t_wordlist *wordlist_create(t_worddesc *word)
|
|||
return (retvalue);
|
||||
}
|
||||
|
||||
/*
|
||||
** free all memory associated with this wordlist.
|
||||
*/
|
||||
void wordlist_destroy(t_wordlist *wordlist)
|
||||
{
|
||||
t_wordlist *prev;
|
||||
|
|
@ -49,11 +40,6 @@ void wordlist_destroy(t_wordlist *wordlist)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** get the worddesc at position idx in the given wordlist.
|
||||
**
|
||||
** return null if out of range or wordlist is null
|
||||
*/
|
||||
t_worddesc *wordlist_get(t_wordlist *wordlist, int idx)
|
||||
{
|
||||
if (wordlist == NULL || idx < 0)
|
||||
|
|
@ -68,16 +54,6 @@ t_worddesc *wordlist_get(t_wordlist *wordlist, int idx)
|
|||
return (wordlist->word);
|
||||
}
|
||||
|
||||
/*
|
||||
** push the given worddesc to the end of the given wordlist.
|
||||
**
|
||||
** if wordlist is null, create a new wordlist.
|
||||
**
|
||||
** returns a pointer to the first element in the wordlist.
|
||||
**
|
||||
** if malloc failure is encountered, all memory for this wordlist is freed, and
|
||||
** null is returned.
|
||||
*/
|
||||
t_wordlist *wordlist_push(t_wordlist *wordlist, t_worddesc *worddesc)
|
||||
{
|
||||
t_wordlist *start;
|
||||
|
|
@ -93,11 +69,6 @@ t_wordlist *wordlist_push(t_wordlist *wordlist, t_worddesc *worddesc)
|
|||
return (start);
|
||||
}
|
||||
|
||||
/*
|
||||
** remove and return the first element in the given wordlist
|
||||
**
|
||||
** If wordlist is empty, return null.
|
||||
*/
|
||||
t_worddesc *wordlist_pop(t_wordlist **wordlist)
|
||||
{
|
||||
t_wordlist *first;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* wordlist.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/09 15:40:23 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/16 15:10:29 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:58:06 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -15,22 +15,9 @@
|
|||
|
||||
# include "../worddesc/worddesc.h"
|
||||
|
||||
/*
|
||||
** Linked-list of WORDS
|
||||
**
|
||||
** cf. section 3.2.4 of https://aosabook.org/en/v1/bash.html
|
||||
**
|
||||
** we are copying how bash does it.
|
||||
*/
|
||||
typedef struct s_wordlist
|
||||
{
|
||||
/*
|
||||
** pointer to the next element in the list
|
||||
*/
|
||||
struct s_wordlist *next;
|
||||
/*
|
||||
** pointer to the word at this position in the list
|
||||
*/
|
||||
struct s_worddesc *word;
|
||||
} t_wordlist;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* wordlist_copy.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/04 12:07:53 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/10 15:05:51 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:55:06 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -14,9 +14,6 @@
|
|||
#include "libft.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// Make a copy of the given wordlist, copying all internal data as well.
|
||||
//
|
||||
// Return null in case of error.
|
||||
t_wordlist *wordlist_copy(const t_wordlist *wordlist)
|
||||
{
|
||||
t_wordlist *outlist;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* wordlist_debug.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/24 18:20:00 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/29 13:05:20 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:55:13 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -14,9 +14,6 @@
|
|||
#include "libft.h"
|
||||
#include "../../treedrawing.h"
|
||||
|
||||
/*
|
||||
** Debug-print a wordlist
|
||||
*/
|
||||
void wordlist_debug(t_wordlist *wordlist, t_buffer *leader, bool is_last)
|
||||
{
|
||||
indent(leader, is_last);
|
||||
|
|
|
|||
|
|
@ -3,21 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* wordlist_idx.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/09 15:14:27 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/10 16:08:43 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:55:27 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "wordlist.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** Remove the element at the given index from the wordlist and return it.
|
||||
**
|
||||
** return null if out of range or wordlist is null
|
||||
*/
|
||||
t_worddesc *wordlist_pop_idx(t_wordlist **wordlist, int idx)
|
||||
{
|
||||
t_wordlist *iter;
|
||||
|
|
@ -47,9 +42,6 @@ t_worddesc *wordlist_pop_idx(t_wordlist **wordlist, int idx)
|
|||
return (free(temp), out);
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove the element at the given index from the wordlist and destroy it.
|
||||
*/
|
||||
void wordlist_destroy_idx(t_wordlist **wordlist, int idx)
|
||||
{
|
||||
worddesc_destroy(wordlist_pop_idx(wordlist, idx));
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/08 17:29:05 by jguelen #+# #+# */
|
||||
/* Updated: 2025/03/20 09:41:04 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:55:53 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -21,15 +21,6 @@ static void ft_swap_wordlist_contents(t_wordlist *list1, t_wordlist *list2)
|
|||
list2->word = tmp_word;
|
||||
}
|
||||
|
||||
/*
|
||||
** The pivot is selected as in classic variations to be the last element of the
|
||||
** list initially.
|
||||
** The partitionning makes it so in the end all elements smaller than the pivot,
|
||||
** which in this case will be determined by a simple order of growing ascii
|
||||
** value on the word->word component of the wordlist, are on the left of the
|
||||
** pivot value and all elements greater on the right.
|
||||
** @RETURN the index at wich the pivot is now to be found.
|
||||
*/
|
||||
static int wordlist_quicksort_partition(t_wordlist *list, int start, int end)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -58,11 +49,6 @@ static int wordlist_quicksort_partition(t_wordlist *list, int start, int end)
|
|||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns the wordlist list sorted in ascending ascii order.
|
||||
** Proceeds by directly swapping the inside contents and not by rewiring the
|
||||
** nodes themselves.
|
||||
*/
|
||||
t_wordlist *wordlist_quicksort(t_wordlist *list, int start, int end)
|
||||
{
|
||||
int pivot;
|
||||
|
|
@ -75,9 +61,6 @@ t_wordlist *wordlist_quicksort(t_wordlist *list, int start, int end)
|
|||
return (list);
|
||||
}
|
||||
|
||||
/*
|
||||
** Is intended as a shortcut for practical use as a full list sort.
|
||||
*/
|
||||
t_wordlist *wordlist_quicksort_full(t_wordlist *list)
|
||||
{
|
||||
return (wordlist_quicksort(list, 0, wordlist_size(list) - 1));
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* wordlist_utils.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/10 09:51:34 by jguelen #+# #+# */
|
||||
/* Updated: 2025/04/30 14:52:32 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:56:55 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,11 +16,6 @@
|
|||
#include "../../../libft/libft.h"
|
||||
#include "../../ft_errno.h"
|
||||
|
||||
/*
|
||||
** Creates a new wordlist composed of only one element. Its next field is NULL
|
||||
** and its word field is a copy of the worddesc passed as a parameter.
|
||||
** Returns NULL in case of error.
|
||||
*/
|
||||
t_wordlist *wordlist_independant_create(t_worddesc *word)
|
||||
{
|
||||
t_wordlist *new;
|
||||
|
|
@ -43,10 +38,6 @@ t_wordlist *wordlist_independant_create(t_worddesc *word)
|
|||
return (new);
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns the number of words present in the wordlist given as parameter.
|
||||
** NOTE: Assumes list not to be circular.
|
||||
*/
|
||||
int wordlist_size(t_wordlist *wordlist)
|
||||
{
|
||||
int size;
|
||||
|
|
@ -69,10 +60,6 @@ t_wordlist *wordlist_last(t_wordlist *list)
|
|||
return (list);
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns the node at index idx in list or NULL if idx is out
|
||||
** of bounds.
|
||||
*/
|
||||
t_wordlist *wordlist_get_elem(t_wordlist *list, int idx)
|
||||
{
|
||||
if (list == NULL || idx < 0)
|
||||
|
|
|
|||
|
|
@ -3,38 +3,26 @@
|
|||
/* ::: :::::::: */
|
||||
/* rule_utils.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/20 12:01:57 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/20 13:18:22 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:58:26 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "rule_utils.h"
|
||||
#include "../matchers/operator_combo.h"
|
||||
|
||||
/*
|
||||
** return true if we are in an unquoted operator state
|
||||
*/
|
||||
bool unquoted_operator(t_token_build *builder)
|
||||
{
|
||||
return (unquoted(builder) && builder->currently_in_operator);
|
||||
}
|
||||
|
||||
/*
|
||||
** return true if we are in an unquoted state
|
||||
*/
|
||||
bool unquoted(t_token_build *builder)
|
||||
{
|
||||
return (builder->quote == '\0');
|
||||
}
|
||||
|
||||
/*
|
||||
** return true if the current char combines with the current token to form an
|
||||
** operator.
|
||||
**
|
||||
** If current token is null, return false
|
||||
*/
|
||||
bool operator_combo(t_token_build *builder, char *original)
|
||||
{
|
||||
if (builder->cur_token == NULL)
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* tokenizing_1_5.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 13:20:01 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/24 14:51:09 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:12:36 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -19,10 +19,6 @@
|
|||
** https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
|
||||
*/
|
||||
|
||||
/*
|
||||
** 1. If the end of input is recognized, the current token (if any) shall be
|
||||
** delimited.
|
||||
*/
|
||||
bool rule_eof(t_token_build *builder, char *original)
|
||||
{
|
||||
if (original[builder->idx] == '\0')
|
||||
|
|
@ -33,11 +29,6 @@ bool rule_eof(t_token_build *builder, char *original)
|
|||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
** 2. If the previous character was used as part of an operator and the current
|
||||
** character is not quoted and can be used with the previous characters to form
|
||||
** an operator, it shall be used as part of that (operator) token.
|
||||
*/
|
||||
bool rule_combine_operator(t_token_build *builder, char *original)
|
||||
{
|
||||
if (unquoted_operator(builder) && operator_combo(builder, original))
|
||||
|
|
@ -49,11 +40,6 @@ bool rule_combine_operator(t_token_build *builder, char *original)
|
|||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
** 3. If the previous character was used as part of an operator and the current
|
||||
** character cannot be used with the previous characters to form an operator,
|
||||
** the operator containing the previous character shall be delimited.
|
||||
*/
|
||||
bool rule_operator_end(t_token_build *builder, char *original)
|
||||
{
|
||||
if (unquoted_operator(builder) && !operator_combo(builder, original))
|
||||
|
|
@ -64,15 +50,6 @@ bool rule_operator_end(t_token_build *builder, char *original)
|
|||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
** 4. If the current character is single-quote, or double-quote and it is not
|
||||
** quoted, it shall affect quoting for subsequent characters up to the end of
|
||||
** the quoted text. The rules for quoting are as described in Quoting . The
|
||||
** result token shall contain exactly the characters that appear in the input,
|
||||
** unmodified, including any embedded or enclosing quotes or substitution
|
||||
** operators, between the <quotation-mark> and the end of the quoted text. The
|
||||
** token shall not be delimited by the end of the quoted field.
|
||||
*/
|
||||
bool rule_quote(t_token_build *builder, char *original)
|
||||
{
|
||||
if (is_quote(original[builder->idx]))
|
||||
|
|
@ -87,22 +64,6 @@ bool rule_quote(t_token_build *builder, char *original)
|
|||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
** 5. If the current character is an unquoted '$' or '`', the shell shall
|
||||
** identify the start of any candidates for parameter expansion (Parameter
|
||||
** Expansion), command substitution (Command Substitution), or arithmetic
|
||||
** expansion (Arithmetic Expansion) from their introductory unquoted character
|
||||
** sequences: '$' or "${", "$(" or '`', and "$((", respectively. The shell shall
|
||||
** read sufficient input to determine the end of the unit to be expanded (as
|
||||
** explained in the cited sections). While processing the characters, if
|
||||
** instances of expansions or quoting are found nested within the substitution,
|
||||
** the shell shall recursively process them in the manner specified for the
|
||||
** construct that is found. The characters found from the beginning of the
|
||||
** substitution to its end, allowing for any recursion necessary to recognize
|
||||
** embedded constructs, shall be included unmodified in the result token,
|
||||
** including any embedded or enclosing substitution operators or quotes. The
|
||||
** token shall not be delimited by the end of the substitution.
|
||||
*/
|
||||
bool rule_var_substitution(t_token_build *builder, char *original)
|
||||
{
|
||||
if (original[builder->idx] == '$' && builder->quote != '\'')
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* tokenizing_6_10.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 13:21:18 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/20 13:14:21 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:59:55 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -14,18 +14,11 @@
|
|||
#include "rule_utils.h"
|
||||
#include "../matchers/operator_start.h"
|
||||
#include "../matchers/blank.h"
|
||||
|
||||
/*
|
||||
** cf. Token Recognition section at
|
||||
** https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
|
||||
*/
|
||||
|
||||
/*
|
||||
** 6. If the current character is not quoted and can be used as the first
|
||||
** character of a new operator, the current token (if any) shall be delimited.
|
||||
** The current character shall be used as the beginning of the next (operator)
|
||||
** token.
|
||||
*/
|
||||
bool rule_new_operator(t_token_build *builder, char *original)
|
||||
{
|
||||
if (unquoted(builder) && is_operator_start(original[builder->idx]))
|
||||
|
|
@ -37,10 +30,6 @@ bool rule_new_operator(t_token_build *builder, char *original)
|
|||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
** 7. If the current character is an unquoted <blank>, any token containing the
|
||||
** previous character is delimited and the current character shall be discarded.
|
||||
*/
|
||||
bool rule_delimit_blank(t_token_build *builder, char *original)
|
||||
{
|
||||
if (unquoted(builder) && is_blank(original[builder->idx]))
|
||||
|
|
@ -52,10 +41,6 @@ bool rule_delimit_blank(t_token_build *builder, char *original)
|
|||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
** 8. If the previous character was part of a word, the current character shall
|
||||
** be appended to that word.
|
||||
*/
|
||||
bool rule_combine_word(t_token_build *builder, char *original)
|
||||
{
|
||||
if (builder->currently_in_word)
|
||||
|
|
@ -67,9 +52,6 @@ bool rule_combine_word(t_token_build *builder, char *original)
|
|||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
** 10. The current character is used as the start of a new word.
|
||||
*/
|
||||
bool rule_new_word(t_token_build *builder, char *original)
|
||||
{
|
||||
new_word(builder, original[builder->idx]);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/21 12:29:36 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/24 16:48:19 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:00:12 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -22,16 +22,6 @@ static void set_quote_error(char quote)
|
|||
ft_errno(FT_EUNCLOSED_SMPL_QUOTE);
|
||||
}
|
||||
|
||||
/*
|
||||
** split a string into words, respecting quotes etc.
|
||||
**
|
||||
** cf. Token Recognition section at
|
||||
** https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
|
||||
**
|
||||
** words are separated with <blanks>, which are defined here
|
||||
** https://pubs.opengroup.org/onlinepubs/9699919799/
|
||||
** section 7.3.1 LC_CTYPE
|
||||
*/
|
||||
t_wordlist *minishell_wordsplit(char *original)
|
||||
{
|
||||
t_token_build token_build;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* expand_wildcard.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/03 19:28:28 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/30 15:09:59 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:00:43 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -65,9 +65,6 @@ static t_redirect *redirect_expand_wildcards(t_redirect *in_list)
|
|||
return (out_list);
|
||||
}
|
||||
|
||||
/*
|
||||
** returns null on error
|
||||
*/
|
||||
static t_wordlist *wordlist_expand_wildcards(t_wordlist *inlist)
|
||||
{
|
||||
t_wordlist *outlist;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* sig.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/20 10:26:05 by jguelen #+# #+# */
|
||||
/* Updated: 2025/04/17 12:05:07 by kcolin ### ########.fr */
|
||||
/* Created: 2025/05/02 12:16:37 by kcolin #+# #+# */
|
||||
/* Updated: 2025/05/02 13:01:42 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -14,19 +14,8 @@
|
|||
#include "signal.h"
|
||||
#include "sig_handlers.h"
|
||||
|
||||
/*
|
||||
** g_signum exists to store the value of a signal if relevant for later
|
||||
** processing.
|
||||
** NOTE: g_signum starts at 0 and should be set back to 0 after the information
|
||||
** it stores has been properly processed.
|
||||
*/
|
||||
int g_signum = 0;
|
||||
|
||||
/*
|
||||
** Catches SIGINT and SIGQUIT.
|
||||
** Set to ignore SIGQUIT and catch SIGINT to set g_signum for
|
||||
** further processing when in interactive mode.
|
||||
*/
|
||||
int set_interactive_mode_sig_handling(void)
|
||||
{
|
||||
struct sigaction sig_act;
|
||||
|
|
@ -38,16 +27,12 @@ int set_interactive_mode_sig_handling(void)
|
|||
return (-1);
|
||||
if (sigaction(SIGINT, &sig_act, NULL) == -1)
|
||||
return (-1);
|
||||
sig_act.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGQUIT, &sig_act, NULL) == -1)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set to ignore SIGINT and SIGQUIT signals if they are generated through
|
||||
** a call to kill when the program is currently executing commands.
|
||||
** Otherwise set g_signum to the number corresponding to the caught signal.
|
||||
*/
|
||||
int set_exec_mode_sig_handling(void)
|
||||
{
|
||||
struct sigaction sig_act;
|
||||
|
|
@ -65,11 +50,6 @@ int set_exec_mode_sig_handling(void)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set to ignore SIGINT and SIGQUIT signals if they are generated through
|
||||
** a call to kill when the program is currently executing commands.
|
||||
** Otherwise set g_signum to the number corresponding to the caught signal.
|
||||
*/
|
||||
int set_here_doc_mode_sig_handling(void)
|
||||
{
|
||||
struct sigaction sig_act;
|
||||
|
|
|
|||
|
|
@ -3,20 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* sig.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 18:21:55 by jguelen #+# #+# */
|
||||
/* Updated: 2025/04/17 12:05:05 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:01:49 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef SIG_H
|
||||
# define SIG_H
|
||||
|
||||
/*
|
||||
** Needed to have the definitions relative to sigaction and siginfo
|
||||
** correctly taken into account.
|
||||
*/
|
||||
# define _POSIX_C_SOURCE 200809L
|
||||
|
||||
# include "libft.h"
|
||||
|
|
@ -32,6 +28,5 @@ extern int g_signum;
|
|||
int set_interactive_mode_sig_handling(void);
|
||||
int set_exec_mode_sig_handling(void);
|
||||
int set_here_doc_mode_sig_handling(void);
|
||||
void readline_reset(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* sig_handlers.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/17 12:01:39 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/29 15:13:42 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:01:15 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -17,9 +17,6 @@
|
|||
#include "sig.h"
|
||||
#include "libft.h"
|
||||
|
||||
/*
|
||||
** redisplay prompt
|
||||
*/
|
||||
void sig_interactive(int signum)
|
||||
{
|
||||
if (signum == SIGINT)
|
||||
|
|
@ -28,23 +25,30 @@ void sig_interactive(int signum)
|
|||
ft_printf("\n");
|
||||
rl_on_new_line();
|
||||
rl_redisplay();
|
||||
g_signum = signum;
|
||||
}
|
||||
}
|
||||
|
||||
void readline_reset(void)
|
||||
int get_sig_retvalue(void)
|
||||
{
|
||||
rl_replace_line("", 0);
|
||||
ft_printf("\n");
|
||||
rl_redisplay();
|
||||
int retvalue;
|
||||
|
||||
retvalue = 128 + g_signum;
|
||||
g_signum = 0;
|
||||
return (retvalue);
|
||||
}
|
||||
|
||||
/*
|
||||
** Stores the value of the caught signal in g_signum for later processing.
|
||||
*/
|
||||
void sig_cmd(int signum, siginfo_t *siginfo, void *context)
|
||||
{
|
||||
(void)context;
|
||||
(void)siginfo;
|
||||
if (signum == SIGQUIT)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "Quit (core dumped)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
ft_printf("\n");
|
||||
}
|
||||
g_signum = signum;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/17 12:01:25 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/17 12:03:07 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 12:03:53 by kcolin ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
# include "signal.h"
|
||||
|
||||
void sig_interactive(int signum);
|
||||
void readline_reset(void);
|
||||
int get_sig_retvalue(void);
|
||||
void sig_cmd(int signum, siginfo_t *siginfo, void *context);
|
||||
|
||||
#endif // SIG_HANDLERS_H
|
||||
|
|
|
|||
|
|
@ -3,19 +3,15 @@
|
|||
/* ::: :::::::: */
|
||||
/* path_split.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/14 10:07:47 by jguelen #+# #+# */
|
||||
/* Updated: 2025/03/14 12:54:49 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:02:15 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "path_split.h"
|
||||
|
||||
/*
|
||||
** We do not ignore empty words here. The word count is therefore the number of
|
||||
** times the separator appears + 1 or 0 if the string s is NULL.
|
||||
*/
|
||||
static size_t paths_count(const char *s, const char sep)
|
||||
{
|
||||
size_t count;
|
||||
|
|
@ -46,13 +42,6 @@ void path_split_destroy(char **split)
|
|||
free(split);
|
||||
}
|
||||
|
||||
/*
|
||||
** Copies and returns in a malloc-allocated string the first "word" of *s.
|
||||
** the first word is defined here as the longest substring of *s starting at
|
||||
** the beginning of *s and not including any c character.
|
||||
** During this process it moves *s past the next c character.
|
||||
** NOTE: '\0' should never be considered a valid separator.
|
||||
*/
|
||||
static char *ft_dup_firstword(char **s, const char c)
|
||||
{
|
||||
char *first_word;
|
||||
|
|
@ -68,19 +57,6 @@ static char *ft_dup_firstword(char **s, const char c)
|
|||
return (first_word);
|
||||
}
|
||||
|
||||
/*
|
||||
** A modified version of a common word-split but that does not ignore NULL
|
||||
** entries i.e. if PATH is of the form
|
||||
** PATH=/usr/bin:::/bin
|
||||
** the result will be {"/usr/bin", "", "", "/bin", NULL}
|
||||
** where all elements except the terminating NULL has been malloc-allocated to
|
||||
** ensure an ease of both treatment and end-detection.
|
||||
** The parameter separator is maintained even if in our specific case it is
|
||||
** expected to simply be ':'.
|
||||
** @Retun Returns a NULL-terminated array when each entry correspond to a
|
||||
** the longest substring possible between separator characters or end of string
|
||||
** in the normal case. Returns NULL in case of an allocation error.
|
||||
*/
|
||||
char **path_split(char const *s, const char separator)
|
||||
{
|
||||
char **split;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* path_split.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/14 10:11:29 by jguelen #+# #+# */
|
||||
/* Updated: 2025/03/14 12:20:27 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:02:30 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,16 +16,6 @@
|
|||
# include <stdlib.h>
|
||||
# include "libft.h"
|
||||
|
||||
/*
|
||||
** A modified version of a common word-split but that does not ignore NULL
|
||||
** entries i.e. if PATH is of the form
|
||||
** PATH=/usr/bin:::/bin
|
||||
** the resul will be {"/usr/bin", "", "", "/bin", NULL}
|
||||
** where all elements except the terminating NULL has been malloc-allocated to
|
||||
** ensure an ease of both treatment and end-detection.
|
||||
** The parameter separator is maintained even if in our specific case it is
|
||||
** expected to simply be ':'.
|
||||
*/
|
||||
char **path_split(const char *s, char separator);
|
||||
void path_split_destroy(char **split);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,19 +6,12 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/25 13:02:59 by jguelen #+# #+# */
|
||||
/* Updated: 2025/03/14 09:55:09 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:02:37 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "replace_substr.h"
|
||||
|
||||
/*
|
||||
** @RETURN Returns a new C-compliant malloc-allocated string corresponding to
|
||||
** text where the substring starting in text at index index_start and ending
|
||||
** at index_end is replaced in totality by the C-compliant string replacement
|
||||
** excluding its NULL-byte.
|
||||
** Returns NULL if an allocation error occurred.
|
||||
*/
|
||||
char *replace_in_str(const char *text, size_t index_start, size_t index_end,
|
||||
const char *replacement)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* simple_filename_exp.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/02 13:40:10 by jguelen #+# #+# */
|
||||
/* Updated: 2025/04/24 17:58:39 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:03:26 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -18,13 +18,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*
|
||||
** Returns a malloc-allocated string representing the full path to
|
||||
** the command or executable corresponding to name or NULL in case of
|
||||
** failure and sets ft_errno in accordance.
|
||||
** NOTE: if name contains a '/' character then name is considered to
|
||||
** be an absolute path.
|
||||
*/
|
||||
char *get_cmdpath(const char *name, t_minishell *app)
|
||||
{
|
||||
char *cmd_path;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/18 18:40:14 by jguelen #+# #+# */
|
||||
/* Updated: 2025/03/19 16:34:10 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:03:20 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -19,10 +19,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*
|
||||
** Returns a malloc-allocated string corresponding to
|
||||
** "path_dir/name"
|
||||
*/
|
||||
char *alloc_path(char *path_dir, char *name)
|
||||
{
|
||||
char *path;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* simple_filename_exp_utils_utils.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/24 17:56:47 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/25 15:42:20 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:03:10 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,13 +16,6 @@
|
|||
#include "subst.h"
|
||||
#include "path_split.h"
|
||||
|
||||
/*
|
||||
** The return value of this function is always safe to destroy with
|
||||
** path_split_destroy.
|
||||
** Returns a NULL-terminated array containing each possible path contained
|
||||
** in the PATH environnement variable.
|
||||
** Returns NULL in case of an allocation error.
|
||||
*/
|
||||
char **get_paths_array(t_env *env)
|
||||
{
|
||||
char **path_array;
|
||||
|
|
@ -42,20 +35,6 @@ char **get_paths_array(t_env *env)
|
|||
return (path_array);
|
||||
}
|
||||
|
||||
/*
|
||||
** Utility function that attempts to find a regular executable file for which
|
||||
** the execution rights are granted. It disregards non-regular files and so in
|
||||
** particular directories (note that using stat allows us to follow symlinks to
|
||||
** their target if encountered). If a file is found here for which the execution
|
||||
** permission is not granted and no elligible file was found before its path is
|
||||
** stored inside oldpath so that in case no file is found to be executable it
|
||||
** is the value stored in oldpath that will be used resulting in a Permission
|
||||
** denied error. oldpath is to store the first occurrence of a regular file
|
||||
** corresponding to the filepath but not executable.
|
||||
**
|
||||
** We disregard all stat(2) failures, since bash does the same and treats them
|
||||
** all to mean that the file does not exist.
|
||||
*/
|
||||
static char *select_path(char *filepath, char **oldpath, char **path,
|
||||
struct stat *fstat)
|
||||
{
|
||||
|
|
@ -77,19 +56,6 @@ static char *select_path(char *filepath, char **oldpath, char **path,
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function exists to implement the bash behaviour specific to where
|
||||
** the PATH variable has been set with a non-empty value.
|
||||
** It checks the working directory if there is a void inside PATH and tries to
|
||||
** find the executable command inside the path entry itself otherwise
|
||||
** disregarding directories and selecting the first entry that both exists and
|
||||
** is executable. If no such entry exists but one or more regular file(s)
|
||||
** exist(s) with the correct name in one of the entries (it therefore lacks the
|
||||
** execution permission) this function will return the first found.
|
||||
** Returns NULL if an error occurred or nothing corresponds to filename
|
||||
** in PATH. ft_errno is set in the course of this function to help distinguish
|
||||
** the nature of the case.
|
||||
*/
|
||||
static char *deal_with_filled_path(char *filename, char **path,
|
||||
struct stat *fstat)
|
||||
{
|
||||
|
|
@ -127,19 +93,6 @@ static char *filter_dir(struct stat fstat, char *filepath)
|
|||
return (free(filepath), NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function searches the environment to resolve a full path for an
|
||||
** executable file corresponding to filename. It deals with two types of bash
|
||||
** behaviours: a PATH unset or corresponding to an empty value and a PATH set
|
||||
** and with a non-empty value.
|
||||
** In the first case it searches the current working directory for the file
|
||||
** coorresponding to filename. If no regular file is found it returns NULL and
|
||||
** distinguishes the case where a directory was found corresponding to filename
|
||||
** by setting ft_errno to FT_ISDIR.
|
||||
** The second case is dealt with using deal_with_filled_path (see the function
|
||||
** itself for details).
|
||||
** Returns NULL on error or if nothing is found.
|
||||
*/
|
||||
char *filepath_from_env(char *filename, t_minishell *app)
|
||||
{
|
||||
char *filepath;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* variable_subst.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/19 17:28:29 by kcolin #+# #+# */
|
||||
/* Updated: 2025/04/18 09:22:10 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:05:15 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,35 +16,6 @@
|
|||
#include "replace_substr.h"
|
||||
#include "../env/env_manip.h"
|
||||
|
||||
/*
|
||||
** @Param
|
||||
** word: the worddesc to be modified
|
||||
** i: the index at which the $ marking the start of expansion is located
|
||||
** id_len: the length of the string that constitutes a valid bash
|
||||
** identifier
|
||||
** rep: a malloc-allocated string previously calculated to correspond to
|
||||
** the actual value to set as the expansion
|
||||
** This function exists to actually modify the worddesc word by modifying the
|
||||
** word proper inside but also keep the marker string coherent with these
|
||||
** modifications so that further steps can act properly with the type of
|
||||
** expansion and properly field split (word split in the manual) the result or
|
||||
** not. To this end if an expansion occurs outside quotes every character
|
||||
** resulting from it is marked simply with a '$' character and is subject to
|
||||
** future field splitting. If however, the expansion occurs within double quotes
|
||||
** it is not to be subjected to field splitting in the future and every
|
||||
** character resulting from such an expansion is marked with a '&'.
|
||||
**
|
||||
** cf. https://www.gnu.org/software/bash/manual/bash.html#Quoting
|
||||
** section 3.5.7
|
||||
** The shell scans the results of parameter expansion, command substitution, and
|
||||
** arithmetic expansion that did not occur within double quotes for word
|
||||
** splitting.
|
||||
**
|
||||
** NOTE: It frees the malloc-allocated string rep.
|
||||
**
|
||||
** @RETURN In case of allocation error returns NULL, oterwise returns word
|
||||
** itself.
|
||||
*/
|
||||
static t_worddesc *word_update(t_worddesc *word, size_t i, size_t id_len,
|
||||
char *rep)
|
||||
{
|
||||
|
|
@ -71,11 +42,6 @@ static t_worddesc *word_update(t_worddesc *word, size_t i, size_t id_len,
|
|||
return (word);
|
||||
}
|
||||
|
||||
/*
|
||||
** Calculates the string corresponding to the value of the variable to be
|
||||
** expanded in the word proper and returns it.
|
||||
** The string returned is always malloc-allocated or NULL.
|
||||
*/
|
||||
static char *calculate_replacement(t_worddesc *word, t_minishell *app, size_t i,
|
||||
size_t *id_len)
|
||||
{
|
||||
|
|
@ -106,22 +72,6 @@ static char *calculate_replacement(t_worddesc *word, t_minishell *app, size_t i,
|
|||
return (free(id), rep);
|
||||
}
|
||||
|
||||
/*
|
||||
** @Param word should NOT be NULL.
|
||||
** Replace the word field of the t_worddesc pointer word with a new string
|
||||
** corresponding to the replacement of the '$' followed by a valid bash
|
||||
** identifier with the corresponding value if present in env, the return value
|
||||
** of the last foreground executed pipeline in the case of $? or nothing if
|
||||
** the corresponding identifier does not have an entry in env.
|
||||
** Similarly if the character following the '$' is neither '_' or
|
||||
** alphanumerical the dollar is removed except for the appearance of a '\0'
|
||||
** signaling the end of the word.
|
||||
** Returns NULL and sets errno in case of error, or the worddesc pointer word
|
||||
** itself if everything went normally.
|
||||
**
|
||||
** returns NULL and does not touch errno if this word should be deleted (because
|
||||
** of the expansion of an unquoted empty variable).
|
||||
*/
|
||||
t_worddesc *word_var_expansion(t_worddesc *word, t_minishell *app)
|
||||
{
|
||||
size_t i;
|
||||
|
|
@ -149,15 +99,6 @@ t_worddesc *word_var_expansion(t_worddesc *word, t_minishell *app)
|
|||
return (word);
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns the t_wordlist passed as a parameter where the words have been
|
||||
** modified to contain strings that represent the result of parameter expansion
|
||||
** where the introductory '$' character was not single quoted.
|
||||
** We DO NOT take the '\' character into account as an escape character here
|
||||
** under any circumstance per subject requirement.
|
||||
**
|
||||
** In case of error, all of list is freed.
|
||||
*/
|
||||
t_wordlist *wordlist_var_expansion(t_wordlist *list, t_minishell *app)
|
||||
{
|
||||
t_wordlist *in_list;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/06 13:03:41 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/19 09:03:31 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:03:56 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -16,11 +16,6 @@
|
|||
#include "../env/env.h"
|
||||
#include "../../libft/libft.h"
|
||||
|
||||
/*
|
||||
** Returns a C-compliant malloc-allocated string of length len and composed
|
||||
** only of the character c except for the terminating NULL-byte or NULL in
|
||||
** case of an allocation error.
|
||||
*/
|
||||
char *construct_repeting_char_string(char c, size_t len)
|
||||
{
|
||||
char *new;
|
||||
|
|
@ -32,24 +27,11 @@ char *construct_repeting_char_string(char c, size_t len)
|
|||
return (new);
|
||||
}
|
||||
|
||||
/*
|
||||
** @RETURN Returns a malloc-allocated string representing the return value of
|
||||
** the last foreground executed pipeline.
|
||||
*/
|
||||
char *expand_question_mark(t_minishell *app)
|
||||
{
|
||||
return (ft_itoa(app->last_return_value));
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns the longest possible substring present in str starting at the
|
||||
** beginning that follows the definition of a valid bash identifier.
|
||||
** NOTE(reminder): a valid bash identifier (name) is a non-empty string
|
||||
** starting with a '_' or an alphabetic character and composed only of '_'s or
|
||||
** alphanumerical characters.
|
||||
** The returned string is malloc-allocated.
|
||||
** In case of an allocation error, NULL is returned.
|
||||
*/
|
||||
char *ft_get_longest_identifier(char *str)
|
||||
{
|
||||
char *key;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* wildcard_exp.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/20 15:01:38 by jguelen #+# #+# */
|
||||
/* Updated: 2025/04/30 14:53:30 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:08:40 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -14,17 +14,12 @@
|
|||
#include "../ft_errno.h"
|
||||
#include "subst.h"
|
||||
#include "replace_substr.h"
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* NOTE: The use of errno and the setting of it was OKed by Alexandru */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
|
||||
/******************************************************************************/
|
||||
/* */
|
||||
/* NOTE: The use of errno and the setting of it was OKed by Alexandru in this */
|
||||
/* context. */
|
||||
/* */
|
||||
/******************************************************************************/
|
||||
/*
|
||||
** Returns a directory stream corresponding to the current directory.
|
||||
**
|
||||
*/
|
||||
static DIR *open_current_dir(void)
|
||||
{
|
||||
char *cur_dir_path;
|
||||
|
|
@ -51,13 +46,6 @@ static DIR *open_current_dir(void)
|
|||
return (dir);
|
||||
}
|
||||
|
||||
/*
|
||||
** Adds filename to the end of the wordlist *list by creating a worddesc whose
|
||||
** word is filename and marker makes filename be considered fully single
|
||||
** quoted.
|
||||
** NOTE: In case of error, this function destroys *list in a similar fashion
|
||||
** as worddesc_create destroys its first parameter in case of failure.
|
||||
*/
|
||||
t_wordlist *add_file_to_list(t_wordlist **list, char *filename)
|
||||
{
|
||||
t_worddesc *file_desc;
|
||||
|
|
@ -81,20 +69,6 @@ t_wordlist *add_file_to_list(t_wordlist **list, char *filename)
|
|||
return (*list);
|
||||
}
|
||||
|
||||
/*
|
||||
** A function designed to present all possible * or ? filename expansions
|
||||
** for the current directory. (? is not asked by the subject).
|
||||
** Does not take into account any other wildcard and does only search the
|
||||
** current working directory.
|
||||
** @PARAM A C compliant character string representing a pattern for a filename.
|
||||
** @RETURN Returns a wordlist for which each entry corresponds to a filename
|
||||
** that matches pattern->word if any file matches in the current directory.
|
||||
** Otherwise return file_pattern itself if nothing matches the perceived
|
||||
** pattern. This list should be alphabetically sorted.
|
||||
** Can return NULL only in case of error.
|
||||
** NOTE: this function never becomes the owner of file_pattern to maintain
|
||||
** coherency of use.
|
||||
*/
|
||||
static t_wordlist *expand_star_core(t_worddesc *file_pattern)
|
||||
{
|
||||
struct dirent *new;
|
||||
|
|
@ -120,17 +94,6 @@ static t_wordlist *expand_star_core(t_worddesc *file_pattern)
|
|||
return (wordlist_quicksort_full(file_wordlist));
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns 1 if and only if filename is recognized by pattern, 0
|
||||
** otherwise or -1 in case of error.
|
||||
** Takes only into account the * wildcard or ?, those characters
|
||||
** NOTE: for a pattern to accept '.' as the first character of a filename
|
||||
** it must be explicitly matched (only for the first character though).
|
||||
** Similarly, '/' is never to be matched except if given explicitly as per
|
||||
** bash requirement. This is a note in case of future expansion as in our case
|
||||
** here we do not have to deal with that since we concern ourselves only with
|
||||
** the current working directory.
|
||||
*/
|
||||
char fits_pattern(char *str, t_worddesc *pattern)
|
||||
{
|
||||
char **pattern_check;
|
||||
|
|
|
|||
|
|
@ -3,19 +3,16 @@
|
|||
/* ::: :::::::: */
|
||||
/* wildcard_exp_utils.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/21 13:46/14 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/24 13:51:30 by jguelen ### ########.fr */
|
||||
/* Created: 2025/03/21 13:46:14 by kcolin #+# #+# */
|
||||
/* Updated: 2025/05/02 13:06:22 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "subst.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
** Cleanly disposes of a pattern checker two dimensionnal array.
|
||||
*/
|
||||
void destroy_pattern_check(char **pattern_check, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
|
@ -29,17 +26,6 @@ void destroy_pattern_check(char **pattern_check, size_t len)
|
|||
free(pattern_check);
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns 1 if the currently examined characters in str and pattern can match
|
||||
** allowing to preserve the validity of previous matches one "character" behind
|
||||
** in both strings.
|
||||
** i.e. serves to detect when the currently examined character of str in index i
|
||||
** and the current character of pattern match exactly or the character in
|
||||
** pattern under scrutiny is an unquoted '?'. There is one exception to wit
|
||||
** the character '.' can only be matched exactly if it is the first character of
|
||||
** both str and pattern and explicitly given. That is in this case ? cannot
|
||||
** match it even if it can under all other circumstance.
|
||||
*/
|
||||
static int same_character_or_one_char_wild(char *str, t_worddesc *pattern,
|
||||
size_t i, size_t j)
|
||||
{
|
||||
|
|
@ -50,9 +36,6 @@ static int same_character_or_one_char_wild(char *str, t_worddesc *pattern,
|
|||
&& pattern->marker[j - 1] != '&'));
|
||||
}
|
||||
|
||||
/*
|
||||
** Condition to know if the wildcard '*' can catch something.
|
||||
*/
|
||||
static int at_star_in_pattern(char *str, t_worddesc *pattern,
|
||||
size_t i, size_t j)
|
||||
{
|
||||
|
|
@ -64,10 +47,6 @@ static int at_star_in_pattern(char *str, t_worddesc *pattern,
|
|||
&& pattern->marker[j - 1] != '&');
|
||||
}
|
||||
|
||||
/*
|
||||
** Sets true where the pattern would match an empty string (the most basic
|
||||
** prefix of str).
|
||||
*/
|
||||
static void init_pattern_checker(t_worddesc *pattern, char **checker)
|
||||
{
|
||||
size_t i;
|
||||
|
|
@ -84,48 +63,6 @@ static void init_pattern_checker(t_worddesc *pattern, char **checker)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Fills the table which contains in its most low and right cell 0 if
|
||||
** str does not match the pattern and 1 otherwise.
|
||||
** This construction is only done for the current diectory so no special
|
||||
** treatment is to be considered for '/' characters which otherwise have
|
||||
** to be matched explicitely. We do however consider the case where the '.'
|
||||
** character cannot be matched except explicitely when in first position
|
||||
** in str.
|
||||
** This function has the goal of building an array of prefix recognition
|
||||
** where each and every cell i,j in the array corresponds to the matching of the
|
||||
** prefix str[0 .. i - 1] with pattern[0 .. j - 1].
|
||||
** the array has the form:
|
||||
** empty string will be noted ε.
|
||||
** pattern | | p[0] | . . . | p[pattern_len - 1]
|
||||
** _s_\_(p)_|___________________|__________|_______|____________________
|
||||
** i \ j | 0 | 1 | . . . | pattern_len
|
||||
** _____\___|___________________|__________|_______|____________________
|
||||
** 0 | ε == ε | | | pattern == ε
|
||||
** _________|___________________|__________|_______|____________________
|
||||
** 1 | str[0..0] == ε |str[0..0] | |
|
||||
** | |== p[0..0]| | pattern == p[0..0]
|
||||
** _________|___________________|__________|_______|____________________
|
||||
** . | | | |
|
||||
** . | | | |
|
||||
** . | | | |
|
||||
** _________|___________________|__________|_______|____________________
|
||||
** str len|| str == ε | str == | |
|
||||
** [len - 1]| | p[0..0] | | pattern == str
|
||||
**
|
||||
** There are several ways to preserve a match while going forward either in str,
|
||||
** in pattern or both: either you are matching corresponding characters or a '?'
|
||||
** wildcard in pattern with str or you are considering a '*' wildcard in
|
||||
** pattern. In those cases you can inherit from a match previously reached.
|
||||
** Otherwise, no match can be found.
|
||||
** When considering two characters that are identical (or '?' in pattern) you
|
||||
** will match exactly if amd only if you matched one character before in both
|
||||
** strings.
|
||||
** In the case of the consideration of the '*' wildcard in pattern, since it
|
||||
** matches both ε and any arbitrary string, you will match if before seeing the
|
||||
** '*' in pattern you already matched (case ε i.e. checker[i-1][j]) or if you
|
||||
** englobe the character currently considered in str (checker[i][j - 1]).
|
||||
*/
|
||||
void build_pattern_checks(char *str, t_worddesc *pattern,
|
||||
char **checker)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/15 15:09:56 by jguelen #+# #+# */
|
||||
/* Updated: 2025/04/30 14:04:57 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:06:44 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -14,10 +14,6 @@
|
|||
#include "subst.h"
|
||||
#include "replace_substr.h"
|
||||
|
||||
/*
|
||||
** Removes unquoted quotes and from file_pattern->word and keeps
|
||||
** file_pattern->marker congruent.
|
||||
*/
|
||||
void clean_pattern(t_worddesc *file_pattern)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -42,13 +38,6 @@ void clean_pattern(t_worddesc *file_pattern)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Checks if a worddesc is to be considered a pattern as bash would in a
|
||||
** reduced capacity, to wit if it contains at least one unquoted '?' or '*'
|
||||
** character.
|
||||
** Returns 1 if the worddesc pointed to by desc is to be considered a pattern,
|
||||
** 0 otherwise.
|
||||
*/
|
||||
int ispattern(t_worddesc *desc)
|
||||
{
|
||||
size_t i;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
/* ::: :::::::: */
|
||||
/* treedrawing.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/18 12:24:25 by kcolin #+# #+# */
|
||||
/* Updated: 2025/03/19 13:50:37 by kcolin ### ########.fr */
|
||||
/* Updated: 2025/05/02 13:11:33 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -21,11 +21,6 @@
|
|||
# define VERTICAL " │ "
|
||||
# define SPACE " "
|
||||
|
||||
/* # define CROSS " |- " */
|
||||
/* # define CORNER " \\- " */
|
||||
/* # define VERTICAL " | " */
|
||||
/* # define SPACE " " */
|
||||
|
||||
void indent(t_buffer *indent, bool is_last);
|
||||
void dedent(t_buffer *indent, bool is_last);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* word_search.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/02 14:27:58 by jguelen #+# #+# */
|
||||
/* Updated: 2025/03/02 18:12:00 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "word_search.h"
|
||||
|
||||
/*
|
||||
** @PARAM needle_len must be the length of the string needle.
|
||||
** Calculates the Knuth-Morris-Pratt array for the word needle to then determine
|
||||
** what shifts to make later for the searching window of the searching of needle
|
||||
** in a text in the future.
|
||||
** Returns the KMP array for needle or NULL if an allocation error occurs or
|
||||
** needle is either NULL or needle_len is 0.
|
||||
*/
|
||||
static int *create_kmp_array(char *needle, size_t needle_len)
|
||||
{
|
||||
int *kmp;
|
||||
size_t i;
|
||||
int j;
|
||||
|
||||
if (!needle || !needle_len)
|
||||
return (NULL);
|
||||
i = 0;
|
||||
j = -1;
|
||||
kmp = malloc((needle_len + 1) * sizeof(int));
|
||||
if (!kmp)
|
||||
return (NULL);
|
||||
kmp[0] = -1;
|
||||
while (i < needle_len)
|
||||
{
|
||||
while (j > -1 && needle[i] != needle[j])
|
||||
j = kmp[j];
|
||||
i++;
|
||||
j++;
|
||||
if (needle[i] == needle[j])
|
||||
kmp[i] = kmp[j];
|
||||
else
|
||||
kmp[i] = j;
|
||||
}
|
||||
return (kmp);
|
||||
}
|
||||
|
||||
/*
|
||||
** @Param Should only be provided with arguments that are neither NULL or empty
|
||||
** Could be extended to report all occurrences of needle in haystack
|
||||
** but for now only reports the first.
|
||||
** (cf http://monge.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080)
|
||||
*/
|
||||
ssize_t word_search_kmp(char *haystack, char *needle)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int *kmp;
|
||||
int needle_len;
|
||||
int haystack_len;
|
||||
|
||||
needle_len = ft_strlen(needle);
|
||||
kmp = create_kmp_array(needle, needle_len);
|
||||
if (!kmp)
|
||||
return (-2);
|
||||
i = 0;
|
||||
j = 0;
|
||||
haystack_len = ft_strlen(haystack);
|
||||
while (j < haystack_len)
|
||||
{
|
||||
while (i > -1 && needle[i] != haystack[j])
|
||||
i = kmp[i];
|
||||
j++;
|
||||
if (++i >= needle_len)
|
||||
return (free(kmp), j - i);
|
||||
}
|
||||
free(kmp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Should not be given NULL or empty arguments.
|
||||
*/
|
||||
ssize_t word_search_brute(char *haystack, char *needle)
|
||||
{
|
||||
ssize_t i;
|
||||
ssize_t needle_len;
|
||||
ssize_t haystack_len;
|
||||
|
||||
needle_len = ft_strlen(needle);
|
||||
haystack_len = ft_strlen(haystack);
|
||||
i = 0;
|
||||
while (i <= (haystack_len - needle_len))
|
||||
{
|
||||
if (ft_memcmp(haystack + i, needle, needle_len) == 0)
|
||||
return (i);
|
||||
i++;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* word_search.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/02 14:10:36 by jguelen #+# #+# */
|
||||
/* Updated: 2025/03/02 17:56:02 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef WORD_SEARCH_H
|
||||
# define WORD_SEARCH_H
|
||||
|
||||
# include <stdlib.h>
|
||||
# include "libft.h"
|
||||
|
||||
/*
|
||||
** An implementation of the Knuth, Morris and Pratt algorithm for exact word
|
||||
** searching in a text.
|
||||
** cf. http://monge.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080
|
||||
**
|
||||
** The design of the Knuth-Morris-Pratt algorithm follows a tight analysis of
|
||||
** the Morris and Pratt algorithm. Let us look more closely at the Morris-Pratt
|
||||
** algorithm. It is possible to improve the length of the shifts.
|
||||
**
|
||||
** Consider an attempt at a left position j, that is when the the window is
|
||||
** positioned on the text factor y[j .. j + m - 1]. Assume that the first
|
||||
** mismatch occurs between x[i] and y[i+j] with 0 < i < m. Then,
|
||||
** x[0 .. i - 1] = y[j .. i + j - 1] = u and a = x[i] != y[i + j] = b.
|
||||
**
|
||||
** When shifting, it is reasonable to expect that a prefix v of the pattern
|
||||
** matches some suffix of the portion u of the text. Moreover, if we want to
|
||||
** avoid another immediate mismatch, the character following the prefix v in the
|
||||
** pattern must be different from a. The longest such prefix v is called the
|
||||
** tagged border of u (it occurs at both ends of u followed by different
|
||||
** characters in x).
|
||||
**
|
||||
** This introduces the notation: let kmpNext[i] be the length of the longest
|
||||
** border of x[0 .. i - 1] followed by a character c different from x[i] and -1
|
||||
** if no such tagged border exits, for 0 < i leq m. Then, after a shift, the
|
||||
** comparisons can resume between characters x[kmpNext[i]] and y[i+j] without
|
||||
** missing any occurrence of x in y, and avoiding a backtrack on the text
|
||||
** (see figure 7.1). The value of kmpNext[0] is set to -1.
|
||||
** The table kmpNext can be computed in O(m) space and time before the searching
|
||||
** phase, applying the same searching algorithm to the pattern itself, as if
|
||||
** x = y.
|
||||
**
|
||||
** The searching phase can be performed in O(m + n) time. The Knuth-Morris-Pratt
|
||||
** algorithm performs at most 2 * n - 1 text character comparisons during the
|
||||
** searching phase. The delay (maximal number of comparisons for a single text
|
||||
** character) is bounded by log_Phi(m) where Phi is the golden ratio.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Uses the Knuth-Morris-Pratt algorithm.
|
||||
** Returns the index where an occurrence of needle was found in haystack, or
|
||||
** -1 if no such occurrence was found and -2 in case of allocation error.
|
||||
*/
|
||||
ssize_t word_search_kmp(char *haystack, char *needle);
|
||||
/*
|
||||
** The simple, familiar brute force searching algorithm of a word in a text.
|
||||
** Returns the index where an occurrence of needle is found in haystack, or
|
||||
** -1 if no such occurrence exists.
|
||||
*/
|
||||
ssize_t word_search_brute(char *haystack, char *needle);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
# make gets confused if a file with the same name exists in the sources, so some
|
||||
# file are prefixed with test_
|
||||
rawtests = \
|
||||
test_here_doc \
|
||||
expansion \
|
||||
test_cmdlist_use_after_free \
|
||||
test_wordlist_idx \
|
||||
test_quote_removal \
|
||||
test_metacharacters \
|
||||
test_parse_cmdlists \
|
||||
test_parse_pipelines \
|
||||
test_parse_simple_cmds \
|
||||
test_env_manip \
|
||||
test_word_splitting \
|
||||
|
||||
ifeq ($(CFLAGS),)
|
||||
CFLAGS = -Wall -Wextra -Werror -g
|
||||
endif
|
||||
tests = $(addprefix test_,$(rawtests))
|
||||
run_tests = $(addprefix run_test_,$(rawtests))
|
||||
test_objs = $(addsuffix .o,$(tests))
|
||||
objs := $(addprefix ../,$(objs)) \
|
||||
testutil.o \
|
||||
parse_cmdlist.o \
|
||||
parse_pipeline.o \
|
||||
|
||||
all_objs = $(objs) $(test_objs)
|
||||
deps = $(all_objs:.o=.d)
|
||||
LDLIBS = \
|
||||
-lreadline \
|
||||
-lft
|
||||
LIBFTDIR = ../libft/
|
||||
LIBFT = $(LIBFTDIR)libft.a
|
||||
IFLAGS = -I$(LIBFTDIR)
|
||||
LINCLUDE = -L$(LIBFTDIR)
|
||||
|
||||
.PHONY: run fclean run_test_%
|
||||
|
||||
.NOTPARALLEL: run
|
||||
run: $(run_tests)
|
||||
@echo "Finished running C tests"
|
||||
|
||||
-include $(deps)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $(IFLAGS) -o $*.o $*.c
|
||||
$(CC) -MM $(CFLAGS) $(IFLAGS) -MT $*.o $*.c > $*.d
|
||||
|
||||
test_%: %.o $(objs)
|
||||
$(CC) $(CFLAGS) -rdynamic -o $@ $*.o $(objs) $(LINCLUDE) $(LDLIBS)
|
||||
|
||||
run_test_%: test_%
|
||||
@echo
|
||||
@echo "====== Now running test: $* ======"
|
||||
@echo
|
||||
./test_$*
|
||||
@echo "====== End of test: $* ======"
|
||||
|
||||
fclean:
|
||||
rm -f $(tests)
|
||||
|
|
@ -1 +0,0 @@
|
|||
echo hello exp
|
||||
|
|
@ -1 +0,0 @@
|
|||
echo hello
|
||||
|
|
@ -1 +0,0 @@
|
|||
echo hello
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* expansion.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/04/09 15:50/06 by khais #+# #+# */
|
||||
/* Updated: 2025/04/09 15:50:06 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "testutil.h"
|
||||
#include "../src/subst/replace_substr.h"
|
||||
#include "../src/subst/subst.h"
|
||||
#include "../src/env/env.h"
|
||||
#include "../src/env/env_manip.h"
|
||||
#include "../src/parser/wordsplit/wordsplit.h"
|
||||
#include "../src/parser/wordlist/wordlist.h"
|
||||
|
||||
/*
|
||||
** Test file for the different expansion/substitution types of minishell.
|
||||
*/
|
||||
|
||||
static void test_replace_in_str_insert(void)
|
||||
{
|
||||
char *line;
|
||||
|
||||
// insertion is not supported, we must replace at least one char
|
||||
line = replace_in_str("le canari qui fait cuicui", 3, 3, "petit ");
|
||||
assert_strequal("le petit anari qui fait cuicui", line);
|
||||
free(line);
|
||||
}
|
||||
|
||||
static void test_insert_instr(void)
|
||||
{
|
||||
char *line;
|
||||
|
||||
line = replace_in_str("abcdefghijk", 1, 4, "souris");
|
||||
assert_strequal("asourisfghijk", line);
|
||||
free(line);
|
||||
line = replace_in_str("abcdefgh" , 2, 2, "non ce n'est pas ma faute");
|
||||
assert_strequal("abnon ce n'est pas ma fautedefgh", line);
|
||||
free(line);
|
||||
line = replace_in_str("le petit canari qui fait cuicui", 3, 8, "");
|
||||
assert_strequal("le canari qui fait cuicui", line);
|
||||
free(line);
|
||||
line = replace_in_str("le petit canari qui fait cuicui", 3, 8, NULL);
|
||||
assert_strequal("le canari qui fait cuicui", line);
|
||||
free(line);
|
||||
line = replace_in_str("le canari qui fait cuicui", 2, 2, " petit ");
|
||||
assert_strequal("le petit canari qui fait cuicui", line);
|
||||
free(line);
|
||||
// premier charactere debut du remplacement
|
||||
line = replace_in_str("le petit canari qui fait cuicui", 0, 1, "Le");
|
||||
assert_strequal("Le petit canari qui fait cuicui", line);
|
||||
free(line);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
/*
|
||||
** NOTE/REMINDER: I currently replace $0 to $9 with nothing but I can change
|
||||
** this behavior at any point if you would rather we ignored them and therefore
|
||||
** did not replace those.
|
||||
*/
|
||||
static void test_env_variable_expansion(void)
|
||||
{
|
||||
t_wordlist *list;
|
||||
t_minishell *app;
|
||||
char *value;
|
||||
char *key;
|
||||
|
||||
value = ft_strdup("/home/jguelen/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin");
|
||||
key = ft_strdup("PATH");
|
||||
app = ft_calloc(1, sizeof(t_minishell));
|
||||
app->env = env_set_entry(&(app->env), key, value);
|
||||
key = ft_strdup("USER");
|
||||
value = ft_strdup("jguelen");
|
||||
app->env = env_set_entry(&(app->env), key, value);
|
||||
list = minishell_wordsplit("$USER$USER $PATH \"'$USER'$USER\" a$test'b' '$USER'");
|
||||
list = wordlist_var_expansion(list, app);
|
||||
assert_strequal("jguelenjguelen", list->word->word);
|
||||
assert_strequal("/home/jguelen/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin", list->next->word->word);
|
||||
assert_strequal("\"'jguelen'jguelen\"", list->next->next->word->word);
|
||||
assert_strequal("a'b'", list->next->next->next->word->word);
|
||||
assert_strequal("'$USER'", list->next->next->next->next->word->word);
|
||||
wordlist_destroy(list);
|
||||
env_destroy(app->env);
|
||||
free(app);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_env_var_expansion_with_invalid_ident(void)
|
||||
{
|
||||
t_wordlist *list;
|
||||
t_minishell *app;
|
||||
char *value;
|
||||
char *key;
|
||||
|
||||
value = ft_strdup("value");
|
||||
key = ft_strdup("VAR");
|
||||
app = ft_calloc(1, sizeof(t_minishell));
|
||||
app->env = env_set_entry(&(app->env), key, value);
|
||||
list = minishell_wordsplit("$''VAR");
|
||||
list = wordlist_var_expansion(list, app);
|
||||
assert_strequal("''VAR", list->word->word);
|
||||
wordlist_destroy(list);
|
||||
env_destroy(app->env);
|
||||
free(app);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_env_var_expansion_with_trailing_dollar(void)
|
||||
{
|
||||
t_wordlist *list;
|
||||
t_minishell *app;
|
||||
char *value;
|
||||
char *key;
|
||||
|
||||
value = ft_strdup("value");
|
||||
key = ft_strdup("VAR");
|
||||
app = ft_calloc(1, sizeof(t_minishell));
|
||||
app->env = env_set_entry(&(app->env), key, value);
|
||||
list = minishell_wordsplit("$VAR$");
|
||||
list = wordlist_var_expansion(list, app);
|
||||
assert_strequal("value$", list->word->word);
|
||||
wordlist_destroy(list);
|
||||
env_destroy(app->env);
|
||||
free(app);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_cmd_path_expansion(void)
|
||||
{
|
||||
t_minishell *app;
|
||||
char *key;
|
||||
char *value;
|
||||
char *cmdpath;
|
||||
|
||||
key = ft_strdup("PATH");
|
||||
value = ft_strdup("./port:/usr/bin");
|
||||
app = ft_calloc(1, sizeof(t_minishell));
|
||||
app->env = env_set_entry(&(app->env), key, value);
|
||||
cmdpath = get_cmdpath("ls", app);
|
||||
assert_strequal("./port/ls", cmdpath);
|
||||
free(cmdpath);
|
||||
value = ft_strdup(":/usr/bin");
|
||||
key = ft_strdup("PATH");
|
||||
app->env = env_set_entry(&(app->env), key, value);
|
||||
cmdpath = get_cmdpath("ls", app);
|
||||
assert_strequal("./ls", cmdpath);
|
||||
free(cmdpath);
|
||||
cmdpath = get_cmdpath("peekaboo", app);
|
||||
assert(cmdpath == NULL);
|
||||
free(cmdpath);
|
||||
env_destroy(app->env);
|
||||
free(app);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_filename_star_expansion(void)
|
||||
{
|
||||
t_worddesc *filepattern;
|
||||
t_wordlist *expanded;
|
||||
t_wordlist *tmp;
|
||||
|
||||
//test1 Everything except . and ..
|
||||
ft_printf("test_filename_star_expansion\n");
|
||||
filepattern = create_single_word("*");
|
||||
expanded = expand_star(filepattern);
|
||||
tmp = expanded;
|
||||
assert_strequal("aba", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(tmp);
|
||||
assert_strequal("abcda", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(tmp);
|
||||
assert_strequal("aiia", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(tmp);
|
||||
assert_strequal("axr", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(tmp);
|
||||
assert_strequal("directory", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(tmp);
|
||||
assert_strequal("exp", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(tmp);
|
||||
assert_strequal("ls", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(tmp);
|
||||
assert_strequal("port", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(tmp);
|
||||
assert_strequal("yuhbqa", tmp->word->word);
|
||||
tmp = tmp->next;
|
||||
assert(!tmp);
|
||||
wordlist_destroy(expanded);
|
||||
worddesc_destroy(filepattern);
|
||||
//test2
|
||||
filepattern = create_single_word("**a*'b'*a*");
|
||||
expanded = expand_star(filepattern);
|
||||
assert(wordlist_size(expanded) == 2);
|
||||
assert_strequal("aba", expanded->word->word);
|
||||
assert_strequal("abcda", expanded->next->word->word);
|
||||
worddesc_destroy(filepattern);
|
||||
wordlist_destroy(expanded);
|
||||
//test ., .. and .plop
|
||||
filepattern = create_single_word(".*");
|
||||
expanded = expand_star(filepattern);
|
||||
assert(wordlist_size(expanded) == 3);
|
||||
assert_strequal(".", expanded->word->word);
|
||||
assert_strequal("..", expanded->next->word->word);
|
||||
assert_strequal(".plop", expanded->next->next->word->word);
|
||||
worddesc_destroy(filepattern);
|
||||
wordlist_destroy(expanded);
|
||||
//test zero result
|
||||
filepattern = create_single_word("e*x***p*b");
|
||||
expanded = expand_star(filepattern);
|
||||
assert(expanded);
|
||||
assert_strequal(filepattern->word, expanded->word->word);
|
||||
worddesc_destroy(filepattern);
|
||||
wordlist_destroy(expanded);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void simple_sub_test(void)
|
||||
{
|
||||
t_wordlist *list;
|
||||
t_minishell *app;
|
||||
char *value;
|
||||
char *key;
|
||||
|
||||
value = ft_strdup("val");
|
||||
key = ft_strdup("KEY");
|
||||
app = ft_calloc(1, sizeof(t_minishell));
|
||||
app->env = env_set_entry(&(app->env), key, value);
|
||||
list = minishell_wordsplit("v$KEY");
|
||||
list = wordlist_var_expansion(list, app);
|
||||
assert_strequal("vval", list->word->word);
|
||||
wordlist_destroy(list);
|
||||
env_destroy(app->env);
|
||||
free(app);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_env_var_expansion_with_trailing_dollar();
|
||||
test_env_var_expansion_with_invalid_ident();
|
||||
test_replace_in_str_insert();
|
||||
if (chdir("./expand_test") == -1)
|
||||
assert("chdir failure" && false);
|
||||
simple_sub_test();
|
||||
test_insert_instr();
|
||||
test_env_variable_expansion();
|
||||
test_cmd_path_expansion();
|
||||
test_filename_star_expansion();
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
input
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
input
|
||||
EOF
|
||||
|
|
@ -1 +0,0 @@
|
|||
EOF
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
hello
|
||||
$USER
|
||||
end
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* parse_cmdlist.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/11 15:54:43 by khais #+# #+# */
|
||||
/* Updated: 2025/03/18 15:05:39 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "../src/parser/cmdlist/cmdlist.h"
|
||||
#include "../src/parser/wordsplit/wordsplit.h"
|
||||
#include "libft.h"
|
||||
#include "unistd.h"
|
||||
#include <assert.h>
|
||||
|
||||
t_cmdlist *parse_cmdlist(char *input)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "Now checking command list with input [%s]\n", input);
|
||||
t_wordlist *words = minishell_wordsplit(input);
|
||||
t_cmdlist *cmd = cmdlist_from_wordlist(words);
|
||||
wordlist_destroy(words);
|
||||
return (cmd);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* parse_cmdlist.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/11 15:55:10 by khais #+# #+# */
|
||||
/* Updated: 2025/03/18 15:05:25 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef PARSE_CMDLIST_H
|
||||
# define PARSE_CMDLIST_H
|
||||
|
||||
# include "../src/parser/cmdlist/cmdlist.h"
|
||||
|
||||
t_cmdlist *parse_cmdlist(char *input);
|
||||
|
||||
#endif // PARSE_CMDLIST_H
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* parse_pipeline.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/11 16:01:48 by khais #+# #+# */
|
||||
/* Updated: 2025/03/11 16:24:41 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "../src/parser/wordsplit/wordsplit.h"
|
||||
#include "../src/parser/pipeline/pipeline.h"
|
||||
#include <assert.h>
|
||||
|
||||
t_pipeline *parse_pipeline(char *input)
|
||||
{
|
||||
t_wordlist *words = minishell_wordsplit(input);
|
||||
t_pipeline *pipeline = pipeline_from_wordlist(words);
|
||||
wordlist_destroy(words);
|
||||
return (pipeline);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* parse_pipeline.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/11 16:01:00 by khais #+# #+# */
|
||||
/* Updated: 2025/03/11 16:02:15 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef PARSE_PIPELINE_H
|
||||
# define PARSE_PIPELINE_H
|
||||
|
||||
# include "../src/parser/pipeline/pipeline.h"
|
||||
|
||||
t_pipeline *parse_pipeline(char *input);
|
||||
|
||||
#endif // PARSE_PIPELINE_H
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* test_cmdlist_use_after_free.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/03 11:40:37 by khais #+# #+# */
|
||||
/* Updated: 2025/03/18 15:05:18 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "../src/parser/wordsplit/wordsplit.h"
|
||||
#include "../src/parser/cmdlist/cmdlist.h"
|
||||
#include "libft.h"
|
||||
#include <assert.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
t_cmdlist *cmd;
|
||||
cmd = NULL;
|
||||
words = minishell_wordsplit("|");
|
||||
cmd = cmdlist_from_wordlist(words);
|
||||
wordlist_destroy(words);
|
||||
assert(cmd == NULL);
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* test_env_manip.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/18 15:11:14 by khais #+# #+# */
|
||||
/* Updated: 2025/02/19 16:41:53 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "../src/env/env.h"
|
||||
#include "../src/env/env_convert.h"
|
||||
#include "../src/env/env_manip.h"
|
||||
#include "../src/env/envp.h"
|
||||
#include "../src/ft_errno.h"
|
||||
#include "libft.h"
|
||||
#include "unistd.h"
|
||||
#include <assert.h>
|
||||
|
||||
static void test_envp_parsing(char *line, char *expected_key, char *expected_value)
|
||||
{
|
||||
char *got_key = envp_get_key(line);
|
||||
char *got_value = envp_get_val(line);
|
||||
ft_dprintf(STDERR_FILENO, "for envp value '%s', expecting key to eq '%s', and got '%s'\n", line, expected_key, got_key);
|
||||
assert(expected_key == got_key || ft_strcmp(expected_key, got_key) == 0);
|
||||
ft_dprintf(STDERR_FILENO, "for envp value '%s', expecting value to eq '%s', and got '%s'\n", line, expected_value, got_value);
|
||||
assert(expected_value == got_value || ft_strcmp(expected_value, got_value) == 0);
|
||||
free(got_key);
|
||||
free(got_value);
|
||||
}
|
||||
|
||||
static void assert_env_value(t_env *env, char *key, char *value)
|
||||
{
|
||||
char *got_value = env_get_val(env, key);
|
||||
ft_dprintf(STDERR_FILENO, "expecting %s=%s to exist, and got %s=%s\n", key, value, key, got_value);
|
||||
assert(ft_strcmp(value, got_value) == 0);
|
||||
}
|
||||
|
||||
static void test_env_set_entry_empty_env(void)
|
||||
{
|
||||
t_env *env;
|
||||
|
||||
env = NULL;
|
||||
assert(env_set_entry(&env, ft_strdup("VAR"), ft_strdup("hello")) != NULL);
|
||||
assert_env_value(env, "VAR", "hello");
|
||||
assert(1 == env_get_size(env));
|
||||
env_destroy(env);
|
||||
}
|
||||
|
||||
static void test_env_set_entry_existing_value(void)
|
||||
{
|
||||
t_env *env;
|
||||
|
||||
env = NULL;
|
||||
assert(env_set_entry(&env, ft_strdup("VAR"), ft_strdup("hello")) != NULL);
|
||||
assert(env_set_entry(&env, ft_strdup("VAR"), ft_strdup("there")) != NULL);
|
||||
assert_env_value(env, "VAR", "there");
|
||||
assert(1 == env_get_size(env));
|
||||
env_destroy(env);
|
||||
}
|
||||
|
||||
static void test_env_set_entry_multiple(void)
|
||||
{
|
||||
t_env *env;
|
||||
|
||||
env = NULL;
|
||||
assert(env_set_entry(&env, ft_strdup("VAR"), ft_strdup("hello")) != NULL);
|
||||
assert(env_set_entry(&env, ft_strdup("SHELL"), ft_strdup("/bin/bash")) != NULL);
|
||||
assert(env_set_entry(&env, ft_strdup("TERM"), ft_strdup("xterm-kitty")) != NULL);
|
||||
assert_env_value(env, "VAR", "hello");
|
||||
assert_env_value(env, "SHELL", "/bin/bash");
|
||||
assert_env_value(env, "TERM", "xterm-kitty");
|
||||
assert(3 == env_get_size(env));
|
||||
env_destroy(env);
|
||||
}
|
||||
|
||||
static void test_env_set_entry_nullargs(void)
|
||||
{
|
||||
t_env *env;
|
||||
|
||||
env = NULL;
|
||||
assert(env_set_entry(&env, ft_strdup("VAR"), ft_strdup("hello")) != NULL);
|
||||
ft_errno(FT_ESUCCESS);
|
||||
assert(env_set_entry(&env, NULL, ft_strdup("hello")) == NULL);
|
||||
assert(ft_errno_get() == FT_EINVAL);
|
||||
assert(env_set_entry(&env, ft_strdup("VAR"), NULL) == NULL);
|
||||
ft_errno(FT_ESUCCESS);
|
||||
assert(env_set_entry(&env, ft_strdup(""), ft_strdup("value")) == NULL);
|
||||
assert(ft_errno_get() == FT_EBADID);
|
||||
assert_env_value(env, "VAR", "hello");
|
||||
assert(1 == env_get_size(env));
|
||||
env_destroy(env);
|
||||
}
|
||||
|
||||
static void test_env_from_envp(void)
|
||||
{
|
||||
|
||||
t_env *env;
|
||||
char *envp[] = {"VAR=hello", "SHELL=/bin/bash", "TERM=xterm-kitty", NULL};
|
||||
|
||||
env = env_from_envp(envp);
|
||||
assert(env != NULL);
|
||||
assert_env_value(env, "VAR", "hello");
|
||||
assert_env_value(env, "SHELL", "/bin/bash");
|
||||
assert_env_value(env, "TERM", "xterm-kitty");
|
||||
assert(3 == env_get_size(env));
|
||||
env_destroy(env);
|
||||
}
|
||||
|
||||
static void test_env_from_envp_invalid(void)
|
||||
{
|
||||
|
||||
t_env *env;
|
||||
char *envp[] = {"VAR=hello", "", "TERM=xterm-kitty", NULL};
|
||||
|
||||
ft_dprintf(STDERR_FILENO, "test_env_from_envp\n");
|
||||
env = env_from_envp(envp);
|
||||
assert(env == NULL);
|
||||
}
|
||||
|
||||
static void test_envp_from_env(void)
|
||||
{
|
||||
t_env *env;
|
||||
char *envp[] = {"VAR=hello", "SHELL=/bin/bash", "TERM=xterm-kitty", NULL};
|
||||
|
||||
env = env_from_envp(envp);
|
||||
char **got_envp = envp_from_env(env);
|
||||
t_env *got_env = env_from_envp(got_envp);
|
||||
assert(got_env != NULL);
|
||||
assert_env_value(got_env, "VAR", "hello");
|
||||
assert_env_value(got_env, "SHELL", "/bin/bash");
|
||||
assert_env_value(got_env, "TERM", "xterm-kitty");
|
||||
assert(3 == env_get_size(got_env));
|
||||
env_destroy(env);
|
||||
env_destroy(got_env);
|
||||
envp_destroy(got_envp);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_envp_parsing("SHELL=/bin/fish", "SHELL", "/bin/fish");
|
||||
test_envp_parsing("=/bin/fish", "", "/bin/fish");
|
||||
test_envp_parsing(NULL, NULL, NULL);
|
||||
test_envp_parsing("", NULL, NULL);
|
||||
test_envp_parsing("VARNAME", "VARNAME", "");
|
||||
test_env_set_entry_empty_env();
|
||||
test_env_set_entry_existing_value();
|
||||
test_env_set_entry_multiple();
|
||||
test_env_set_entry_nullargs();
|
||||
test_env_from_envp();
|
||||
test_env_from_envp_invalid();
|
||||
test_envp_from_env();
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* test_here_doc.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/03/07 11:43:32 by khais #+# #+# */
|
||||
/* Updated: 2025/04/08 16:34:50 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <assert.h>
|
||||
#include "testutil.h"
|
||||
#include "libft.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "../src/executing/here_doc/here_doc.h"
|
||||
#include "../src/env/env_manip.h"
|
||||
#include "../src/ft_errno.h"
|
||||
|
||||
static void test_here_doc_filename_generation(void)
|
||||
{
|
||||
char *filename1;
|
||||
char *filename2;
|
||||
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
ft_errno(FT_ESUCCESS);
|
||||
filename1 = here_doc_random_filename();
|
||||
filename2 = here_doc_random_filename();
|
||||
assert(filename1 != NULL);
|
||||
assert(filename2 != NULL);
|
||||
ft_dprintf(STDERR_FILENO, "Got filename: [%s]\n", filename1);
|
||||
ft_dprintf(STDERR_FILENO, "Got filename: [%s]\n", filename2);
|
||||
assert(ft_strcmp(filename1, filename2) != 0);
|
||||
free(filename1);
|
||||
free(filename2);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_here_doc_invalid_args(void)
|
||||
{
|
||||
t_worddesc *marker;
|
||||
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
ft_errno(FT_ESUCCESS);
|
||||
assert(-1 == here_doc(NULL, 0, NULL));
|
||||
marker = worddesc_create(NULL, 0, NULL, WORD_TOKEN);
|
||||
assert(-1 == here_doc(marker, 0, NULL));
|
||||
worddesc_destroy(marker);
|
||||
marker = worddesc_create(ft_strdup("EOF"), 0, NULL, WORD_TOKEN);
|
||||
assert(-1 == here_doc(marker, -1, NULL));
|
||||
worddesc_destroy(marker);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_here_doc_only_end_marker(void)
|
||||
{
|
||||
t_worddesc *marker;
|
||||
int infile;
|
||||
int result;
|
||||
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
ft_errno(FT_ESUCCESS);
|
||||
marker = worddesc_create(ft_strdup("EOF"), 0, NULL, WORD_TOKEN);
|
||||
infile = open("./here_doc_only_eof.input", O_RDONLY);
|
||||
result = here_doc(marker, infile, NULL);
|
||||
close(infile);
|
||||
assert(result != -1);
|
||||
assert(NULL == get_next_line(result));
|
||||
close(result);
|
||||
worddesc_destroy(marker);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_here_doc_input_plus_end_marker(void)
|
||||
{
|
||||
t_worddesc *marker;
|
||||
int infile;
|
||||
int result;
|
||||
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
ft_errno(FT_ESUCCESS);
|
||||
marker = worddesc_create(ft_strdup("EOF"), 0, NULL, WORD_TOKEN);
|
||||
infile = open("./here_doc_input_plus_eof.input", O_RDONLY);
|
||||
result = here_doc(marker, infile, NULL);
|
||||
close(infile);
|
||||
worddesc_destroy(marker);
|
||||
assert(result != -1);
|
||||
assert_strequal("input\n", get_next_line(result));
|
||||
close(result);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_here_doc_input_no_end_marker(void)
|
||||
{
|
||||
t_worddesc *marker;
|
||||
int infile;
|
||||
int result;
|
||||
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
marker = worddesc_create(ft_strdup("EOF"), 0, NULL, WORD_TOKEN);
|
||||
infile = open("./here_doc_input_no_eof.input", O_RDONLY);
|
||||
result = here_doc(marker, infile, NULL);
|
||||
close(infile);
|
||||
worddesc_destroy(marker);
|
||||
assert(result != -1);
|
||||
assert_strequal("input\n", get_next_line(result));
|
||||
close(result);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_here_doc_with_expansion(void)
|
||||
{
|
||||
t_worddesc *marker;
|
||||
int infile;
|
||||
int result;
|
||||
t_minishell app;
|
||||
|
||||
ft_bzero(&app, sizeof(t_minishell));
|
||||
app.env = env_set_entry(&app.env, ft_strdup("USER"), ft_strdup("kcolin"));
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
ft_errno(FT_ESUCCESS);
|
||||
marker = worddesc_create(ft_strdup("EOF"), 0, NULL, WORD_TOKEN);
|
||||
infile = open("./here_doc_with_expansion.input", O_RDONLY);
|
||||
result = here_doc(marker, infile, &app);
|
||||
close(infile);
|
||||
worddesc_destroy(marker);
|
||||
assert(result != -1);
|
||||
assert_strequal("hello\n", get_next_line(result));
|
||||
assert_strequal("kcolin\n", get_next_line(result));
|
||||
assert_strequal("end\n", get_next_line(result));
|
||||
close(result);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
static void test_here_doc_with_no_expansion(void)
|
||||
{
|
||||
t_worddesc *marker;
|
||||
int infile;
|
||||
int result;
|
||||
t_minishell app;
|
||||
|
||||
ft_bzero(&app, sizeof(t_minishell));
|
||||
app.env = env_set_entry(&app.env, ft_strdup("USER"), ft_strdup("kcolin"));
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
marker = worddesc_create(ft_strdup("EOF"), W_QUOTED, NULL, WORD_TOKEN);
|
||||
infile = open("./here_doc_with_expansion.input", O_RDONLY);
|
||||
result = here_doc(marker, infile, &app);
|
||||
close(infile);
|
||||
worddesc_destroy(marker);
|
||||
assert(result != -1);
|
||||
assert_strequal("hello\n", get_next_line(result));
|
||||
assert_strequal("$USER\n", get_next_line(result));
|
||||
assert_strequal("end\n", get_next_line(result));
|
||||
close(result);
|
||||
do_leak_check();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_here_doc_filename_generation();
|
||||
test_here_doc_invalid_args();
|
||||
test_here_doc_only_end_marker();
|
||||
test_here_doc_input_plus_end_marker();
|
||||
test_here_doc_input_no_end_marker();
|
||||
test_here_doc_with_expansion();
|
||||
test_here_doc_with_no_expansion();
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* metacharacters.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kcolin <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/06 15:21:00 by kcolin #+# #+# */
|
||||
/* Updated: 2025/02/11 18:32:01 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "../src/parser/matchers/metacharacter.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void test_metacharacters(void)
|
||||
{
|
||||
dup2(STDERR_FILENO, STDIN_FILENO);
|
||||
char c = 'a';
|
||||
printf("not metachar:");
|
||||
while (c != 'z')
|
||||
{
|
||||
printf("%c", c);
|
||||
assert(!is_metacharacter(c));
|
||||
c++;
|
||||
}
|
||||
c = 'A';
|
||||
while (c != 'Z')
|
||||
{
|
||||
printf("%c", c);
|
||||
assert(!is_metacharacter(c));
|
||||
c++;
|
||||
}
|
||||
c = '0';
|
||||
while (c != '9')
|
||||
{
|
||||
printf("%c", c);
|
||||
assert(!is_metacharacter(c));
|
||||
c++;
|
||||
}
|
||||
char *not_metachars = ";[]{}*+=_-";
|
||||
int i = 0;
|
||||
while (not_metachars[i] != '\0')
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%c", not_metachars[i]);
|
||||
assert(!is_metacharacter(not_metachars[i]));
|
||||
i++;
|
||||
}
|
||||
char *metachars = " \t\n|&()<>";
|
||||
i = 0;
|
||||
printf("\nmetachar:");
|
||||
while (metachars[i] != '\0')
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%c (%d) ", metachars[i], metachars[i]);
|
||||
assert(is_metacharacter(metachars[i]));
|
||||
i++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_metacharacters();
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* test_parse_cmdlists.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/24 17:40:48 by khais #+# #+# */
|
||||
/* Updated: 2025/03/20 11:57:26 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "ft_printf.h"
|
||||
|
||||
#include "../src/parser/cmdlist/cmdlist.h"
|
||||
#include "testutil.h"
|
||||
#include "unistd.h"
|
||||
#include <assert.h>
|
||||
#include "parse_cmdlist.h"
|
||||
|
||||
static void test_parse_cmdlist_empty(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("");
|
||||
assert(cmd == NULL);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_cmdlist_single_pipeline(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("echo this | cat -e");
|
||||
assert(cmd != NULL);
|
||||
assert_pipelineequal("echo this | cat -e", cmd, 0);
|
||||
assert(cmd->operators[0] == OP_END);
|
||||
assert(cmd->num_cmd == 1);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_cmdlist_simple_and(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("echo this | cat -e && echo works | wc -c");
|
||||
assert(cmd != NULL);
|
||||
assert_pipelineequal("echo this | cat -e", cmd, 0);
|
||||
assert(cmd->operators[0] == OP_AND);
|
||||
assert_pipelineequal("echo works | wc -c", cmd, 1);
|
||||
assert(cmd->num_cmd == 2);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_cmdlist_simple_or(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("echo this | cat -e || echo works | wc -c");
|
||||
assert(cmd != NULL);
|
||||
assert_pipelineequal("echo this | cat -e", cmd, 0);
|
||||
assert(cmd->operators[0] == OP_OR);
|
||||
assert_pipelineequal("echo works | wc -c", cmd, 1);
|
||||
assert(cmd->num_cmd == 2);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_cmdlist_triple_or(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("echo this | cat -e || echo works | wc -c || echo as well | cut -d' ' -f1");
|
||||
assert(cmd != NULL);
|
||||
assert_pipelineequal("echo this | cat -e", cmd, 0);
|
||||
assert(cmd->operators[0] == OP_OR);
|
||||
assert_pipelineequal("echo works | wc -c", cmd, 1);
|
||||
assert(cmd->operators[1] == OP_OR);
|
||||
assert_pipelineequal("echo as well | cut -d' ' -f1", cmd, 2);
|
||||
assert(cmd->num_cmd == 3);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_cmdlist_triple_both_operators(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("echo this | cat -e || echo works | wc -c && echo as well | cut -d' ' -f1");
|
||||
assert(cmd != NULL);
|
||||
assert_pipelineequal("echo this | cat -e", cmd, 0);
|
||||
assert(cmd->operators[0] == OP_OR);
|
||||
assert_pipelineequal("echo works | wc -c", cmd, 1);
|
||||
assert(cmd->operators[1] == OP_AND);
|
||||
assert_pipelineequal("echo as well | cut -d' ' -f1", cmd, 2);
|
||||
assert(cmd->operators[2] == OP_END);
|
||||
assert(cmd->num_cmd == 3);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_cmdlist_quad_both_operators(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("echo this | cat -e || echo works | wc -c && echo as well | cut -d' ' -f1 || echo final");
|
||||
assert(cmd != NULL);
|
||||
assert_pipelineequal("echo this | cat -e", cmd, 0);
|
||||
assert(cmd->operators[0] == OP_OR);
|
||||
assert_pipelineequal("echo works | wc -c", cmd, 1);
|
||||
assert(cmd->operators[1] == OP_AND);
|
||||
assert_pipelineequal("echo as well | cut -d' ' -f1", cmd, 2);
|
||||
assert(cmd->operators[2] == OP_OR);
|
||||
assert_pipelineequal("echo final", cmd, 3);
|
||||
assert(cmd->operators[3] == OP_END);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_cmdlist_invalid_pipeline(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("echo this | | cat -e || echo does not work");
|
||||
assert(cmd == NULL);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_cmdlist_simple_command(void)
|
||||
{
|
||||
ft_dprintf(STDERR_FILENO, "==> %s <==\n", __FUNCTION__);
|
||||
t_cmdlist *cmd = parse_cmdlist("echo this");
|
||||
assert(cmd != NULL);
|
||||
assert_pipelineequal("echo this", cmd, 0);
|
||||
assert(cmd->operators[0] == OP_END);
|
||||
assert(cmd->num_cmd == 1);
|
||||
cmdlist_destroy(cmd);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_parse_cmdlist_empty();
|
||||
do_leak_check();
|
||||
test_parse_cmdlist_single_pipeline();
|
||||
do_leak_check();
|
||||
test_parse_cmdlist_simple_and();
|
||||
do_leak_check();
|
||||
test_parse_cmdlist_simple_or();
|
||||
do_leak_check();
|
||||
test_parse_cmdlist_triple_or();
|
||||
do_leak_check();
|
||||
test_parse_cmdlist_triple_both_operators();
|
||||
do_leak_check();
|
||||
test_parse_cmdlist_quad_both_operators();
|
||||
do_leak_check();
|
||||
test_parse_cmdlist_invalid_pipeline();
|
||||
do_leak_check();
|
||||
test_parse_cmdlist_simple_command();
|
||||
do_leak_check();
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* test_parse_pipelines.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/21 13:13:58 by khais #+# #+# */
|
||||
/* Updated: 2025/03/11 16:33:11 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "../src/parser/pipeline/pipeline.h"
|
||||
#include "../src/ft_errno.h"
|
||||
#include <assert.h>
|
||||
#include "testutil.h"
|
||||
#include <limits.h>
|
||||
#include "parse_pipeline.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static void test_parse_empty_pipeline(void)
|
||||
{
|
||||
t_pipeline *pipeline = parse_pipeline("");
|
||||
assert(pipeline == NULL);
|
||||
pipeline_destroy(pipeline);
|
||||
}
|
||||
|
||||
static void test_parse_pipeline_single_cmd(void)
|
||||
{
|
||||
t_pipeline *pipeline = parse_pipeline("echo hello world");
|
||||
assert(pipeline->num_cmd == 1);
|
||||
assert_pipeline_cmd_word(pipeline, "echo", 0, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "hello", 0, 1);
|
||||
assert_pipeline_cmd_word(pipeline, "world", 0, 2);
|
||||
pipeline_destroy(pipeline);
|
||||
}
|
||||
|
||||
static void test_parse_pipeline_two_cmd(void)
|
||||
{
|
||||
t_pipeline *pipeline = parse_pipeline("echo hello world | tee output.txt");
|
||||
assert_pipeline_cmd_word(pipeline, "echo", 0, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "hello", 0, 1);
|
||||
assert_pipeline_cmd_word(pipeline, "world", 0, 2);
|
||||
assert_pipeline_cmd_word(pipeline, "tee", 1, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "output.txt", 1, 1);
|
||||
pipeline_destroy(pipeline);
|
||||
}
|
||||
|
||||
static void test_parse_pipeline_three_cmd(void)
|
||||
{
|
||||
t_pipeline *pipeline = parse_pipeline("echo hello world | tee output.txt | cat -e");
|
||||
assert_pipeline_cmd_word(pipeline, "echo", 0, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "hello", 0, 1);
|
||||
assert_pipeline_cmd_word(pipeline, "world", 0, 2);
|
||||
assert_pipeline_cmd_word(pipeline, "tee", 1, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "output.txt", 1, 1);
|
||||
assert_pipeline_cmd_word(pipeline, "cat", 2, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "-e", 2, 1);
|
||||
pipeline_destroy(pipeline);
|
||||
}
|
||||
|
||||
static void test_parse_pipeline_four_cmd(void)
|
||||
{
|
||||
t_pipeline *pipeline = parse_pipeline("echo hello world | tee output.txt | cat -e | hexdump -C");
|
||||
assert_pipeline_cmd_word(pipeline, "echo", 0, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "hello", 0, 1);
|
||||
assert_pipeline_cmd_word(pipeline, "world", 0, 2);
|
||||
assert_pipeline_cmd_word(pipeline, "tee", 1, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "output.txt", 1, 1);
|
||||
assert_pipeline_cmd_word(pipeline, "cat", 2, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "-e", 2, 1);
|
||||
assert_pipeline_cmd_word(pipeline, "hexdump", 3, 0);
|
||||
assert_pipeline_cmd_word(pipeline, "-C", 3, 1);
|
||||
pipeline_destroy(pipeline);
|
||||
}
|
||||
|
||||
static void test_parse_pipeline_double_pipe_rejected(void)
|
||||
{
|
||||
ft_errno(FT_ESUCCESS);
|
||||
assert(parse_pipeline("echo hello | | tee output.txt") == NULL);
|
||||
assert(ft_errno_get() == FT_EUNEXPECTED_PIPE);
|
||||
}
|
||||
|
||||
static void test_parse_pipeline_triple_pipe_rejected(void)
|
||||
{
|
||||
ft_errno(FT_ESUCCESS);
|
||||
assert(parse_pipeline("echo hello | | | tee output.txt") == NULL);
|
||||
assert(ft_errno_get() == FT_EUNEXPECTED_PIPE);
|
||||
}
|
||||
|
||||
static void test_parse_pipeline_pipe_at_start_rejected(void)
|
||||
{
|
||||
ft_errno(FT_ESUCCESS);
|
||||
assert(parse_pipeline("| echo hello | tee output.txt") == NULL);
|
||||
assert(ft_errno_get() == FT_EUNEXPECTED_PIPE);
|
||||
}
|
||||
|
||||
static void test_parse_pipeline_pipe_at_end_rejected(void)
|
||||
{
|
||||
ft_errno(FT_ESUCCESS);
|
||||
assert(parse_pipeline("echo hello | tee output.txt |") == NULL);
|
||||
assert(ft_errno_get() == FT_EUNEXPECTED_PIPE);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_parse_empty_pipeline();
|
||||
test_parse_pipeline_single_cmd();
|
||||
test_parse_pipeline_two_cmd();
|
||||
test_parse_pipeline_three_cmd();
|
||||
test_parse_pipeline_four_cmd();
|
||||
test_parse_pipeline_double_pipe_rejected();
|
||||
test_parse_pipeline_triple_pipe_rejected();
|
||||
test_parse_pipeline_pipe_at_start_rejected();
|
||||
test_parse_pipeline_pipe_at_end_rejected();
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* parse_simple_cmds.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/21 12:20:20 by khais #+# #+# */
|
||||
/* Updated: 2025/03/07 12:32:04 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <assert.h>
|
||||
#include "../src/parser/simple_cmd/simple_cmd.h"
|
||||
#include "../src/parser/wordsplit/wordsplit.h"
|
||||
#include "../src/parser/wordlist/wordlist.h"
|
||||
#include "testutil.h"
|
||||
|
||||
static t_simple_cmd *parse_simple_cmd(char *input)
|
||||
{
|
||||
t_wordlist *words = minishell_wordsplit(input);
|
||||
t_simple_cmd *cmd = simple_cmd_from_wordlist(words);
|
||||
return (cmd);
|
||||
}
|
||||
|
||||
static void test_parse_empty_command(void)
|
||||
{
|
||||
t_simple_cmd *cmd = parse_simple_cmd("");
|
||||
assert(cmd != NULL);
|
||||
simple_cmd_destroy(cmd);
|
||||
}
|
||||
|
||||
static void test_parse_nonempty_command(void)
|
||||
{
|
||||
t_simple_cmd *cmd = parse_simple_cmd("echo Hello World!");
|
||||
assert(cmd != NULL);
|
||||
assert_strequal("echo", wordlist_get(cmd->words, 0)->word);
|
||||
assert_strequal("Hello", wordlist_get(cmd->words, 1)->word);
|
||||
assert_strequal("World!", wordlist_get(cmd->words, 2)->word);
|
||||
simple_cmd_destroy(cmd);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_parse_empty_command();
|
||||
test_parse_nonempty_command();
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* test_quote_removal.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/28 13:46:56 by khais #+# #+# */
|
||||
/* Updated: 2025/03/11 16:31:50 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "../src/parser/remove_quotes/remove_quotes.h"
|
||||
#include "testutil.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void test_quote_removal_no_quotes_single_word(void)
|
||||
{
|
||||
t_worddesc *word = create_single_word("word");
|
||||
t_worddesc *got_word = remove_quotes(word);
|
||||
assert_strequal("word", got_word->word);
|
||||
assert(got_word->marker == NULL);
|
||||
worddesc_destroy(word);
|
||||
worddesc_destroy(got_word);
|
||||
}
|
||||
|
||||
static void test_quote_removal_null(void)
|
||||
{
|
||||
t_worddesc *word = NULL;
|
||||
t_worddesc *got_word = remove_quotes(word);
|
||||
assert(got_word == NULL);
|
||||
}
|
||||
|
||||
static void test_quote_removal_single_quotes(void)
|
||||
{
|
||||
t_worddesc *word = create_single_word("'word'");
|
||||
t_worddesc *got_word = remove_quotes(word);
|
||||
assert_strequal("word", got_word->word);
|
||||
assert(got_word->marker == NULL);
|
||||
worddesc_destroy(word);
|
||||
worddesc_destroy(got_word);
|
||||
}
|
||||
|
||||
static void test_quote_removal_double_quotes(void)
|
||||
{
|
||||
t_worddesc *word = create_single_word("\"word\"");
|
||||
t_worddesc *got_word = remove_quotes(word);
|
||||
assert_strequal("word", got_word->word);
|
||||
assert(got_word->marker == NULL);
|
||||
worddesc_destroy(word);
|
||||
worddesc_destroy(got_word);
|
||||
}
|
||||
|
||||
static void test_quote_removal_mixed_single_in_double(void)
|
||||
{
|
||||
t_worddesc *word = create_single_word("\"'word'\"");
|
||||
t_worddesc *got_word = remove_quotes(word);
|
||||
assert_strequal("'word'", got_word->word);
|
||||
assert(got_word->marker == NULL);
|
||||
worddesc_destroy(word);
|
||||
worddesc_destroy(got_word);
|
||||
}
|
||||
|
||||
static void test_quote_removal_mixed_double_in_single(void)
|
||||
{
|
||||
t_worddesc *word = create_single_word("'\"word\"'");
|
||||
t_worddesc *got_word = remove_quotes(word);
|
||||
assert_strequal("\"word\"", got_word->word);
|
||||
assert(got_word->marker == NULL);
|
||||
worddesc_destroy(word);
|
||||
worddesc_destroy(got_word);
|
||||
}
|
||||
|
||||
static void test_quote_removal_middle_of_word(void)
|
||||
{
|
||||
t_worddesc *word = create_single_word("var='VALUE'here");
|
||||
t_worddesc *got_word = remove_quotes(word);
|
||||
assert_strequal("var=VALUEhere", got_word->word);
|
||||
assert(got_word->marker == NULL);
|
||||
worddesc_destroy(word);
|
||||
worddesc_destroy(got_word);
|
||||
}
|
||||
|
||||
static void test_quote_removal_nested_middle_of_word(void)
|
||||
{
|
||||
t_worddesc *word = create_single_word("var=\"'VALUE'here\"");
|
||||
t_worddesc *got_word = remove_quotes(word);
|
||||
assert_strequal("var='VALUE'here", got_word->word);
|
||||
assert(got_word->marker == NULL);
|
||||
worddesc_destroy(word);
|
||||
worddesc_destroy(got_word);
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
test_quote_removal_no_quotes_single_word();
|
||||
test_quote_removal_null();
|
||||
test_quote_removal_single_quotes();
|
||||
test_quote_removal_double_quotes();
|
||||
test_quote_removal_mixed_single_in_double();
|
||||
test_quote_removal_mixed_double_in_single();
|
||||
test_quote_removal_middle_of_word();
|
||||
test_quote_removal_nested_middle_of_word();
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,338 +0,0 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* word_splitting.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/13 15:17:56 by khais #+# #+# */
|
||||
/* Updated: 2025/03/06 16:50:56 by khais ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <assert.h>
|
||||
#include "testutil.h"
|
||||
#include "../src/parser/wordsplit/wordsplit.h"
|
||||
#include <unistd.h>
|
||||
#include "libft.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** https://bash-hackers.gabe565.com/syntax/words/
|
||||
*/
|
||||
static void test_wordsplit_singleword(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("echo");
|
||||
assert_strequal("echo", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert(NULL == wordlist_get(words, 1));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_singleword_with_blanks(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("\t \t echo \t\t ");
|
||||
assert_strequal("echo", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert(NULL == wordlist_get(words, 1));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_multiword(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("\t echo\tThe file is named $MYFILE \t");
|
||||
assert_strequal("echo", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("The", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 1)->marker);
|
||||
assert_strequal("file", wordlist_get(words, 2)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 2)->marker);
|
||||
assert_strequal("is", wordlist_get(words, 3)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 3)->marker);
|
||||
assert_strequal("named", wordlist_get(words, 4)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 4)->marker);
|
||||
assert_strequal("$MYFILE", wordlist_get(words, 5)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 5)->marker);
|
||||
assert(NULL == wordlist_get(words, 6));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_multiword_with_single_quotes(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("\t echo\t' \t The file is named $MYFILE ' \t");
|
||||
assert_strequal("echo", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("' \t The file is named $MYFILE '", wordlist_get(words, 1)->word);
|
||||
// This marker is one char shorter because the tab character above is
|
||||
// represented here with two chars
|
||||
ft_dprintf(STDERR_FILENO, "the marker below is shorter than the string above because the string above contains a tab, it is normal\n");
|
||||
assert_strequal(" '''''''''''''''''''''''''''''''''' ", wordlist_get(words, 1)->marker);
|
||||
assert(NULL == wordlist_get(words, 2));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_multiword_with_double_quotes(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("\t echo\t\" \t The file is named $MYFILE \" \t");
|
||||
assert_strequal("echo", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("\" \t The file is named $MYFILE \"", wordlist_get(words, 1)->word);
|
||||
// This marker is one char shorter because the tab character above is
|
||||
// represented here with two chars
|
||||
ft_dprintf(STDERR_FILENO, "the marker below is shorter than the string above because the string above contains a tab, it is normal\n");
|
||||
assert_strequal(" \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\" ", wordlist_get(words, 1)->marker);
|
||||
assert(NULL == wordlist_get(words, 2));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_mixed_single_in_double(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("hello \"mixed ' \tquotes \t'\" there");
|
||||
assert_strequal("hello", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("\"mixed ' \tquotes \t'\"", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\" ", wordlist_get(words, 1)->marker);
|
||||
assert_strequal("there", wordlist_get(words, 2)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 2)->marker);
|
||||
assert(NULL == wordlist_get(words, 3));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_mixed_double_in_single(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("hello 'mixed \" quotes \"' there");
|
||||
assert_strequal("hello", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("'mixed \" quotes \"'", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" '''''''''''''''' ", wordlist_get(words, 1)->marker);
|
||||
assert_strequal("there", wordlist_get(words, 2)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 2)->marker);
|
||||
assert(NULL == wordlist_get(words, 3));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_mixed_broken(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("hello '\"mixed 'quotes'\"' there");
|
||||
assert_strequal("hello", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("'\"mixed 'quotes'\"'", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" ''''''' ' ", wordlist_get(words, 1)->marker);
|
||||
assert_strequal("there", wordlist_get(words, 2)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 2)->marker);
|
||||
assert(NULL == wordlist_get(words, 3));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_unclosed_single(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("'hello");
|
||||
assert(words == NULL);
|
||||
}
|
||||
|
||||
static void test_wordsplit_unclosed_double(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("\"hello");
|
||||
assert(words == NULL);
|
||||
}
|
||||
|
||||
static void test_wordsplit_operator_word(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit(">test");
|
||||
assert_strequal(">", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("test", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 1)->marker);
|
||||
assert(NULL == wordlist_get(words, 2));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_all_operators(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("|&&||()<>><<>");
|
||||
assert_strequal("|", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("&&", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 1)->marker);
|
||||
assert_strequal("||", wordlist_get(words, 2)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 2)->marker);
|
||||
assert_strequal("(", wordlist_get(words, 3)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 3)->marker);
|
||||
assert_strequal(")", wordlist_get(words, 4)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 4)->marker);
|
||||
assert_strequal("<", wordlist_get(words, 5)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 5)->marker);
|
||||
assert_strequal(">>", wordlist_get(words, 6)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 6)->marker);
|
||||
assert_strequal("<<", wordlist_get(words, 7)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 7)->marker);
|
||||
assert_strequal(">", wordlist_get(words, 8)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 8)->marker);
|
||||
assert(NULL == wordlist_get(words, 9));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_operator_combining(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("|||>>><<<&&&");
|
||||
assert_strequal("||", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert_strequal("|", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 1)->marker);
|
||||
assert_strequal(">>", wordlist_get(words, 2)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 2)->marker);
|
||||
assert_strequal(">", wordlist_get(words, 3)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 3)->marker);
|
||||
assert_strequal("<<", wordlist_get(words, 4)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 4)->marker);
|
||||
assert_strequal("<", wordlist_get(words, 5)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 5)->marker);
|
||||
assert_strequal("&&", wordlist_get(words, 6)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 6)->marker);
|
||||
assert_strequal("&", wordlist_get(words, 7)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 7)->marker);
|
||||
assert(NULL == wordlist_get(words, 8));
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_var_substitution(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("echo VAR=$VAR here");
|
||||
assert_strequal("echo", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert(0 == wordlist_get(words, 0)->flags);
|
||||
assert_strequal("VAR=$VAR", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 1)->marker);
|
||||
assert(W_HASDOLLAR == wordlist_get(words, 1)->flags);
|
||||
assert_strequal("here", wordlist_get(words, 2)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 2)->marker);
|
||||
assert(0 == wordlist_get(words, 2)->flags);
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_var_substitution_quotes(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("VAR=\"$VAR\"");
|
||||
assert_strequal("VAR=\"$VAR\"", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" \"\"\"\" ", wordlist_get(words, 0)->marker);
|
||||
assert(W_HASDOLLAR & wordlist_get(words, 0)->flags);
|
||||
wordlist_destroy(words);
|
||||
words = minishell_wordsplit("VAR='$VAR'");
|
||||
assert_strequal("VAR='$VAR'", wordlist_get(words, 0)->word);
|
||||
assert((W_HASDOLLAR & wordlist_get(words, 0)->flags) == 0);
|
||||
assert_strequal(" '''' ", wordlist_get(words, 0)->marker);
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_quote_detection_nonnested(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
|
||||
words = minishell_wordsplit("echo 'single quotes' here \"double quotes\" here");
|
||||
assert_strequal("echo", wordlist_get(words, 0)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 0)->marker);
|
||||
assert(0 == wordlist_get(words, 0)->flags);
|
||||
assert_strequal("'single quotes'", wordlist_get(words, 1)->word);
|
||||
assert_strequal(" ''''''''''''' ", wordlist_get(words, 1)->marker);
|
||||
assert(W_QUOTED == wordlist_get(words, 1)->flags);
|
||||
assert_strequal("here", wordlist_get(words, 2)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 2)->marker);
|
||||
assert(0 == wordlist_get(words, 2)->flags);
|
||||
assert_strequal("\"double quotes\"", wordlist_get(words, 3)->word);
|
||||
assert_strequal(" \"\"\"\"\"\"\"\"\"\"\"\"\" ", wordlist_get(words, 3)->marker);
|
||||
assert((W_QUOTED | W_DQUOTE) == wordlist_get(words, 3)->flags);
|
||||
assert_strequal("here", wordlist_get(words, 4)->word);
|
||||
assert_strequal(" ", wordlist_get(words, 4)->marker);
|
||||
assert(0 == wordlist_get(words, 4)->flags);
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_quote_detection_nested_double_in_simple(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
char *str;
|
||||
|
||||
str = "'these are single quotes \"with double\" inside'";
|
||||
words = minishell_wordsplit(str);
|
||||
assert_strequal(str, wordlist_get(words, 0)->word);
|
||||
assert_strequal(" '''''''''''''''''''''''''''''''''''''''''''' ", wordlist_get(words, 0)->marker);
|
||||
assert(W_QUOTED == wordlist_get(words, 0)->flags);
|
||||
wordlist_destroy(words);
|
||||
str = "'\"these are single quotes with double inside\"'";
|
||||
words = minishell_wordsplit(str);
|
||||
assert_strequal(str, wordlist_get(words, 0)->word);
|
||||
assert_strequal(" '''''''''''''''''''''''''''''''''''''''''''' ", wordlist_get(words, 0)->marker);
|
||||
assert(W_QUOTED == wordlist_get(words, 0)->flags);
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
static void test_wordsplit_quote_detection_nested_single_in_double(void)
|
||||
{
|
||||
t_wordlist *words;
|
||||
char *str;
|
||||
|
||||
str = "\"these are double quotes 'with single' inside\"";
|
||||
words = minishell_wordsplit(str);
|
||||
assert_strequal(str, wordlist_get(words, 0)->word);
|
||||
assert((W_QUOTED | W_DQUOTE) == wordlist_get(words, 0)->flags);
|
||||
assert_strequal(" \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\" ", wordlist_get(words, 0)->marker);
|
||||
wordlist_destroy(words);
|
||||
str = "\"'these are double quotes with single inside'\"";
|
||||
words = minishell_wordsplit(str);
|
||||
assert_strequal(str, wordlist_get(words, 0)->word);
|
||||
assert_strequal(" \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\" ", wordlist_get(words, 0)->marker);
|
||||
assert((W_QUOTED | W_DQUOTE) == wordlist_get(words, 0)->flags);
|
||||
wordlist_destroy(words);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_wordsplit_singleword();
|
||||
test_wordsplit_singleword_with_blanks();
|
||||
test_wordsplit_multiword();
|
||||
test_wordsplit_multiword_with_single_quotes();
|
||||
test_wordsplit_multiword_with_double_quotes();
|
||||
test_wordsplit_mixed_single_in_double();
|
||||
test_wordsplit_mixed_double_in_single();
|
||||
test_wordsplit_mixed_broken();
|
||||
test_wordsplit_unclosed_single();
|
||||
test_wordsplit_unclosed_double();
|
||||
test_wordsplit_operator_word();
|
||||
test_wordsplit_all_operators();
|
||||
test_wordsplit_operator_combining();
|
||||
test_wordsplit_var_substitution();
|
||||
test_wordsplit_var_substitution_quotes();
|
||||
test_wordsplit_quote_detection_nonnested();
|
||||
test_wordsplit_quote_detection_nested_double_in_simple();
|
||||
test_wordsplit_quote_detection_nested_single_in_double();
|
||||
return (0);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue