Compare commits
3 Commits
3c7ee5b161
...
ff5edf543f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff5edf543f | ||
|
|
518ec87e60 | ||
|
|
6bc2eab19b |
24
AGENTS.md
24
AGENTS.md
@@ -3,6 +3,7 @@
|
||||
## Project Structure & Module Organization
|
||||
- `src/` holds the shell implementation, with submodules for `builtins/`, `executor/`, `parser/`, and `variables/`.
|
||||
- `src/builtins/` currently includes: `cd`, `echo`, `env`, `exit`, `export`, `pwd`, `unset`.
|
||||
- `src/executor/` includes pipeline/process orchestration plus file redirections in `redirections.c`.
|
||||
- `include/` contains public headers used across modules.
|
||||
- `lib/` is populated at build time with third-party 42 libraries (libft, get_next_line, ft_printf, ft_args).
|
||||
- `docs/` stores project references and manual test notes (see `docs/tests.md`).
|
||||
@@ -25,22 +26,25 @@
|
||||
|
||||
## Parser & Lexer Functionality (Current `src/parser`)
|
||||
- Runtime entrypoint is `parse(line, minishell)` from `src/minishell.c` (`readline -> parse -> execute`).
|
||||
- `parse` splits the input line by unquoted `|` using `extract_next_command` + `find_boundary`.
|
||||
- Each non-empty segment is trimmed and converted into a `t_command` via `cmdnew`.
|
||||
- `set_argv` splits by unquoted spaces; quote characters are preserved in the resulting argument text.
|
||||
- `parse` calls `lex(line)` and then converts token lists to `t_command` nodes with `parse_tokens`.
|
||||
- `command_new` builds one command from tokens up to `TOKEN_PIPE`.
|
||||
- `words_add` stores consecutive `TOKEN_WORD` tokens in `command->argv` and increments `argc`.
|
||||
- `expand_envs` is currently a TODO (no `$VAR` expansion is applied in parser stage).
|
||||
- Redirections/heredoc are not converted into `t_command.redirections` yet in `src/parser/parser.c`.
|
||||
- `set_path` resolves builtins and direct paths (`/`, `./`, `../`), otherwise searches `PATH` with `access(..., F_OK)`.
|
||||
- Redirection tokens are converted into `t_redirection` and stored in `t_command.redirections`; heredocs are stored in `t_command.heredocs`.
|
||||
- Path resolution is handled in executor (`executor_resolve_command_path`) before `execve`.
|
||||
- `src/parser/lexer.c` provides a separate lexer (`lex`) that tokenizes into `TOKEN_WORD`, `TOKEN_PIPE`, `TOKEN_REDIRECT_IN`, `TOKEN_REDIRECT_OUT`, `TOKEN_APPEND`, and `TOKEN_HEREDOC`.
|
||||
- The lexer tracks single/double quote context so metacharacters inside quotes remain part of words.
|
||||
- Meta runs are read as contiguous chunks in `read_token` (for example, repeated `|`/`<`/`>` are captured as one token value).
|
||||
- Current parser flow does not consume the lexer output yet.
|
||||
- Current parser flow consumes lexer output directly.
|
||||
|
||||
## Executor Redirections (Current `src/executor`)
|
||||
- File redirections are applied in `src/executor/redirections.c` via `open` + `dup2` before command execution.
|
||||
- Supported file redirections: input `<`, output truncate `>`, output append `>>`.
|
||||
- Redirections are applied for both forked commands (child path) and single builtins executed in parent.
|
||||
- Parent-builtin redirections save/restore `STDIN_FILENO` and `STDOUT_FILENO` after builtin execution.
|
||||
|
||||
## Parser & Lexer Known Gaps
|
||||
- `src/parser/parser.c` currently calls `tokenize()` with no valid declaration/definition in that unit, causing a build error with `-Werror`.
|
||||
- `src/parser/parser.c` writes `command->infile` and `command->outfile`, but those fields are not present in `t_command` (`include/core.h`), causing build errors.
|
||||
- `src/parser/parser.c` keeps a `tokens` variable that is unused, also failing under `-Werror`.
|
||||
- `include/parser.h` exports `parse` only; `lex` is not declared in public headers.
|
||||
- Heredoc tokens are parsed and stored, but runtime heredoc execution/input feeding is still pending in executor.
|
||||
- No explicit unmatched-quote syntax error handling is implemented in parser/lexer path.
|
||||
|
||||
## Testing Guidelines
|
||||
|
||||
@@ -52,5 +52,9 @@ extern void executor_child_process(t_list *node, t_pipeline *pl,
|
||||
extern void executor_parent_cleanup(t_list *node, t_pipeline *pl);
|
||||
extern uint8_t executor_wait_for_children(pid_t last_child_pid);
|
||||
extern void executor_cmdfree(t_command *command);
|
||||
extern bool executor_apply_redirections(const t_command *command,
|
||||
int *saved_stdin, int *saved_stdout);
|
||||
extern void executor_restore_redirections(int saved_stdin,
|
||||
int saved_stdout);
|
||||
|
||||
#endif /* EXECUTOR_H */
|
||||
|
||||
@@ -47,6 +47,8 @@ static bool run_current_command(
|
||||
{
|
||||
bool should_fork;
|
||||
t_command *command;
|
||||
int saved_stdin;
|
||||
int saved_stdout;
|
||||
|
||||
if (executor_create_pipe_if_needed(state->current_command,
|
||||
&state->pipeline) == PIPE_ERROR)
|
||||
@@ -61,7 +63,11 @@ static bool run_current_command(
|
||||
else
|
||||
{
|
||||
command = state->current_command->content;
|
||||
if (!executor_apply_redirections(command, &saved_stdin, &saved_stdout))
|
||||
state->exit_status = EXIT_FAILURE;
|
||||
else
|
||||
state->exit_status = executor_execute_command(command, minishell);
|
||||
executor_restore_redirections(saved_stdin, saved_stdout);
|
||||
}
|
||||
executor_parent_cleanup(state->current_command, &state->pipeline);
|
||||
state->current_command = state->current_command->next;
|
||||
|
||||
@@ -24,6 +24,8 @@ void executor_child_process(
|
||||
command = current_command->content;
|
||||
executor_setup_child_input(pipeline);
|
||||
executor_setup_child_output(current_command, pipeline);
|
||||
if (!executor_apply_redirections(command, NULL, NULL))
|
||||
exit(EXIT_FAILURE);
|
||||
exit_status = executor_execute_command(command, minishell);
|
||||
exit(exit_status);
|
||||
}
|
||||
@@ -85,6 +87,16 @@ static void cmdfree_argv(
|
||||
free(argv);
|
||||
}
|
||||
|
||||
static void cmdfree_redirection(
|
||||
t_redirection *redirection
|
||||
)
|
||||
{
|
||||
if (redirection == NULL)
|
||||
return ;
|
||||
free(redirection->target);
|
||||
free(redirection);
|
||||
}
|
||||
|
||||
void executor_cmdfree(
|
||||
t_command *command
|
||||
)
|
||||
@@ -93,5 +105,8 @@ void executor_cmdfree(
|
||||
return ;
|
||||
cmdfree_argv(command->argv);
|
||||
free(command->path);
|
||||
ft_lstclear(&command->redirections,
|
||||
(void (*)(void *))cmdfree_redirection);
|
||||
ft_lstclear(&command->heredocs, (void (*)(void *))cmdfree_redirection);
|
||||
free(command);
|
||||
}
|
||||
|
||||
111
src/executor/redirections.c
Normal file
111
src/executor/redirections.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* redirections.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/12 00:00:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/12 00:00:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "executor.h"
|
||||
#include <errno.h>
|
||||
|
||||
static int open_redirection_target(
|
||||
const t_redirection *redirection
|
||||
)
|
||||
{
|
||||
if (redirection->type == TOKEN_REDIRECT_IN)
|
||||
return (open(redirection->target, O_RDONLY));
|
||||
if (redirection->type == TOKEN_REDIRECT_OUT)
|
||||
return (open(redirection->target, O_WRONLY | O_CREAT | O_TRUNC, 0644));
|
||||
if (redirection->type == TOKEN_APPEND)
|
||||
return (open(redirection->target, O_WRONLY | O_CREAT | O_APPEND, 0644));
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static bool backup_stream_if_needed(
|
||||
const t_redirection *redirection,
|
||||
int *saved_stdin,
|
||||
int *saved_stdout
|
||||
)
|
||||
{
|
||||
if (redirection->type == TOKEN_REDIRECT_IN && saved_stdin != NULL
|
||||
&& *saved_stdin == -1)
|
||||
{
|
||||
*saved_stdin = dup(STDIN_FILENO);
|
||||
if (*saved_stdin == -1)
|
||||
return (perror("dup"), false);
|
||||
}
|
||||
if ((redirection->type == TOKEN_REDIRECT_OUT
|
||||
|| redirection->type == TOKEN_APPEND) && saved_stdout != NULL
|
||||
&& *saved_stdout == -1)
|
||||
{
|
||||
*saved_stdout = dup(STDOUT_FILENO);
|
||||
if (*saved_stdout == -1)
|
||||
return (perror("dup"), false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool executor_apply_redirections(
|
||||
const t_command *command,
|
||||
int *saved_stdin,
|
||||
int *saved_stdout
|
||||
)
|
||||
{
|
||||
t_list *node;
|
||||
t_redirection *redirection;
|
||||
int fd;
|
||||
|
||||
if (saved_stdin != NULL)
|
||||
*saved_stdin = -1;
|
||||
if (saved_stdout != NULL)
|
||||
*saved_stdout = -1;
|
||||
if (command == NULL || command->redirections == NULL)
|
||||
return (true);
|
||||
node = command->redirections;
|
||||
while (node != NULL)
|
||||
{
|
||||
redirection = (t_redirection *)node->content;
|
||||
if (redirection == NULL || redirection->target == NULL)
|
||||
return (false);
|
||||
if (!backup_stream_if_needed(redirection, saved_stdin, saved_stdout))
|
||||
return (false);
|
||||
fd = open_redirection_target(redirection);
|
||||
if (fd == -1)
|
||||
return (perror(redirection->target), false);
|
||||
if (redirection->type == TOKEN_REDIRECT_IN
|
||||
&& dup2(fd, STDIN_FILENO) == -1)
|
||||
return (close(fd), perror("dup2"), false);
|
||||
if ((redirection->type == TOKEN_REDIRECT_OUT
|
||||
|| redirection->type == TOKEN_APPEND)
|
||||
&& dup2(fd, STDOUT_FILENO) == -1)
|
||||
return (close(fd), perror("dup2"), false);
|
||||
close(fd);
|
||||
node = node->next;
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
void executor_restore_redirections(
|
||||
int saved_stdin,
|
||||
int saved_stdout
|
||||
)
|
||||
{
|
||||
if (saved_stdin != -1)
|
||||
{
|
||||
if (dup2(saved_stdin, STDIN_FILENO) == -1)
|
||||
perror("dup2");
|
||||
close(saved_stdin);
|
||||
}
|
||||
if (saved_stdout != -1)
|
||||
{
|
||||
if (dup2(saved_stdout, STDOUT_FILENO) == -1)
|
||||
perror("dup2");
|
||||
close(saved_stdout);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user