Compare commits
6 Commits
5c33afb20a
...
c95703b42b
| Author | SHA1 | Date | |
|---|---|---|---|
| c95703b42b | |||
| f4cfae1107 | |||
|
|
6453abfda3 | ||
|
|
7862f3e131 | ||
|
|
637391470b | ||
|
|
217505e3b0 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -69,3 +69,5 @@ dkms.conf
|
|||||||
|
|
||||||
# debug information files
|
# debug information files
|
||||||
*.dwo
|
*.dwo
|
||||||
|
|
||||||
|
minishell-codex/
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/10/29 22:09:51 by sede-san #+# #+# */
|
/* Created: 2025/10/29 22:09:51 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/08 19:42:50 by sede-san ### ########.fr */
|
/* Updated: 2026/02/14 01:15:34 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
# include "ft_args.h"
|
# include "ft_args.h"
|
||||||
# include "minishell.h"
|
# include "minishell.h"
|
||||||
# include "core.h"
|
# include "core.h"
|
||||||
|
# include "variables.h"
|
||||||
|
|
||||||
typedef uint8_t (*t_builtin_func)(t_command cmd, t_minishell *minishell);
|
typedef uint8_t (*t_builtin_func)(t_command cmd, t_minishell *minishell);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/10/22 19:10:13 by sede-san #+# #+# */
|
/* Created: 2025/10/22 19:10:13 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/13 20:06:08 by sede-san ### ########.fr */
|
/* Updated: 2026/02/14 01:25:43 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@@ -63,16 +63,9 @@ typedef struct s_redirection
|
|||||||
typedef struct s_variables
|
typedef struct s_variables
|
||||||
{
|
{
|
||||||
t_hashmap *environment;
|
t_hashmap *environment;
|
||||||
// char **internal;
|
t_hashmap *internal;
|
||||||
} t_variables;
|
} t_variables;
|
||||||
|
|
||||||
typedef struct s_prompt
|
|
||||||
{
|
|
||||||
const char *ps1; // primary prompt string
|
|
||||||
const char *ps2; // secondary prompt string for multiline input
|
|
||||||
} t_prompt;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Main minishell structure containing global state information
|
* @brief Main minishell structure containing global state information
|
||||||
*
|
*
|
||||||
@@ -85,7 +78,6 @@ typedef struct s_minishell
|
|||||||
{
|
{
|
||||||
t_variables variables;
|
t_variables variables;
|
||||||
t_hashmap *builtins;
|
t_hashmap *builtins;
|
||||||
t_prompt prompt;
|
|
||||||
uint8_t exit_status;
|
uint8_t exit_status;
|
||||||
bool exit;
|
bool exit;
|
||||||
} t_minishell;
|
} t_minishell;
|
||||||
@@ -150,8 +142,8 @@ extern char **get_envp(t_minishell *msh);
|
|||||||
|
|
||||||
extern void free_envp(char **envp);
|
extern void free_envp(char **envp);
|
||||||
|
|
||||||
extern char *get_env(const char *env_name, t_minishell *msh);
|
void handle_sigint_status(t_minishell *minishell);
|
||||||
|
bool handle_eof(char *line, t_minishell *minishell);
|
||||||
|
|
||||||
extern void unset_env(const char *env_name, t_minishell *msh);
|
|
||||||
|
|
||||||
#endif /* CORE_H */
|
#endif /* CORE_H */
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2026/02/10 22:28:01 by sede-san #+# #+# */
|
/* Created: 2026/02/10 22:28:01 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/10 23:24:16 by sede-san ### ########.fr */
|
/* Updated: 2026/02/14 01:11:38 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@@ -17,7 +17,8 @@
|
|||||||
# include "core.h"
|
# include "core.h"
|
||||||
# include "parser.h"
|
# include "parser.h"
|
||||||
|
|
||||||
extern void syntax_error_unexpected_token(t_token *token);
|
extern void syntax_error_unexpected_token(t_token *token);
|
||||||
extern void malloc_error(void);
|
extern void malloc_error(void);
|
||||||
|
extern void command_not_found_error(const char *command);
|
||||||
|
|
||||||
#endif /* ERRORS_H */
|
#endif /* ERRORS_H */
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/10/20 16:35:10 by sede-san #+# #+# */
|
/* Created: 2025/10/20 16:35:10 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/13 20:12:25 by sede-san ### ########.fr */
|
/* Updated: 2026/02/14 01:13:42 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
|||||||
@@ -23,19 +23,29 @@
|
|||||||
|
|
||||||
// parser.c
|
// parser.c
|
||||||
|
|
||||||
extern t_list *parse(char *line, t_minishell *minishell);
|
extern t_list *parse(char *line, t_minishell *minishell);
|
||||||
|
|
||||||
// lexer.c
|
// lexer.c
|
||||||
|
|
||||||
extern t_list *lex(const char *line);
|
t_token_type get_token_type(const char *str);
|
||||||
|
t_token *token_new(t_token_type type, char *text);
|
||||||
|
t_token *read_token(t_token_type type, const char *line,
|
||||||
|
size_t *i);
|
||||||
|
t_token *read_word(const char *line, size_t *i);
|
||||||
|
|
||||||
extern void token_clear(t_token *token);
|
extern t_list *lex(const char *line);
|
||||||
|
|
||||||
|
extern void token_clear(t_token *token);
|
||||||
extern t_command *command_new(t_list **tokens);
|
extern t_command *command_new(t_list **tokens);
|
||||||
extern void command_clear(t_command *command);
|
extern void command_clear(t_command *command);
|
||||||
extern void command_add_tokens(t_command **command, t_list **tokens);
|
extern void command_add_tokens(t_command **command, t_list **tokens);
|
||||||
extern bool is_pipe(t_token *token);
|
extern bool is_pipe(t_token *token);
|
||||||
extern bool is_redirection(t_token *token);
|
extern bool is_redirection(t_token *token);
|
||||||
void redirection_add(t_list **tokens, t_token *token, t_command **command);
|
void redirection_add(t_list **tokens, t_token *token,
|
||||||
void words_add(t_list **tokens, t_command **command);
|
t_command **command);
|
||||||
|
void words_add(t_list **tokens, t_command **command);
|
||||||
|
|
||||||
|
void expand(t_list **commands, t_minishell *minishell);
|
||||||
|
void redirection_clear(t_redirection *redirection);
|
||||||
|
|
||||||
#endif /* PARSER_H */
|
#endif /* PARSER_H */
|
||||||
|
|||||||
43
include/variables.h
Normal file
43
include/variables.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* variables.h :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:45:35 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/14 01:24:49 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#ifndef VARIABLES_H
|
||||||
|
# define VARIABLES_H
|
||||||
|
|
||||||
|
# include "minishell.h"
|
||||||
|
# include "core.h"
|
||||||
|
|
||||||
|
// variables.c
|
||||||
|
|
||||||
|
extern char *get_var(const char *name, t_minishell *minishell);
|
||||||
|
extern void set_var(const char *name, char *value, t_minishell *minishell);
|
||||||
|
extern void unset_var(const char *name, t_minishell *minishell);
|
||||||
|
|
||||||
|
// environment.c
|
||||||
|
|
||||||
|
extern char *get_env(const char *name, t_minishell *minishell);
|
||||||
|
extern void set_env(const char *name, char *value, t_minishell *minishell);
|
||||||
|
extern void unset_env(const char *name, t_minishell *minishell);
|
||||||
|
|
||||||
|
extern void set_envp(char **envp, t_minishell *minishell);
|
||||||
|
extern char **get_envp(t_minishell *minishell);
|
||||||
|
extern void free_envp(char **envp);
|
||||||
|
|
||||||
|
// internal.c
|
||||||
|
|
||||||
|
extern char *get_int(const char *name, t_minishell *minishell);
|
||||||
|
extern void set_int(const char *name, char *value, t_minishell *minishell);
|
||||||
|
extern void unset_int(const char *name, t_minishell *minishell);
|
||||||
|
|
||||||
|
extern void set_intp(t_minishell *minishell);
|
||||||
|
|
||||||
|
#endif /* VARIABLES_H */
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
NAME := minishell
|
|
||||||
CC := cc
|
|
||||||
CFLAGS := -Wall -Wextra -Werror -g
|
|
||||||
INCLUDES := -Iinclude
|
|
||||||
READLINE_LIBS := -lreadline -lncurses
|
|
||||||
|
|
||||||
SRCS := $(shell find src -name '*.c')
|
|
||||||
OBJS := $(SRCS:src/%.c=build/%.o)
|
|
||||||
|
|
||||||
all: $(NAME)
|
|
||||||
|
|
||||||
$(NAME): $(OBJS)
|
|
||||||
$(CC) $(CFLAGS) $(OBJS) $(READLINE_LIBS) -o $(NAME)
|
|
||||||
|
|
||||||
build/%.o: src/%.c
|
|
||||||
@mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf build
|
|
||||||
|
|
||||||
fclean: clean
|
|
||||||
rm -f $(NAME)
|
|
||||||
|
|
||||||
re: fclean all
|
|
||||||
|
|
||||||
.PHONY: all clean fclean re
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
# Minishell - Guion de defensa (version codex)
|
|
||||||
|
|
||||||
Este guion esta alineado con la estructura real en `minishell-codex/`.
|
|
||||||
|
|
||||||
## 1. Explicacion corta del proyecto
|
|
||||||
- Minishell es un interprete de comandos interactivo.
|
|
||||||
- Implementa pipes, redirecciones, variables y builtins basicos.
|
|
||||||
- Se basa en el flujo: lectura -> lexer -> parser -> expansion -> ejecucion.
|
|
||||||
|
|
||||||
## 2. Flujo completo (paso a paso)
|
|
||||||
1. `readline()` muestra el prompt y devuelve la linea.
|
|
||||||
2. `lex_line()` divide la linea en tokens (`TOK_WORD`, `TOK_PIPE`, redirecciones).
|
|
||||||
3. `parse_tokens()` construye la pipeline con comandos y redirecciones.
|
|
||||||
4. `expand_pipeline()` aplica expansion de `$VAR` y `$?` respetando comillas.
|
|
||||||
5. `execute_pipeline()` resuelve `PATH`, prepara heredocs y ejecuta.
|
|
||||||
|
|
||||||
## 3. Estructuras clave
|
|
||||||
- `t_token`: tipo y texto de tokens (`minishell-codex/include/minishell.h`).
|
|
||||||
- `t_command`: argv, redirecciones, path.
|
|
||||||
- `t_pipeline`: lista de comandos.
|
|
||||||
- `t_redir`: tipo, target y fd.
|
|
||||||
- `t_shell`: estado global (env, exit_status, flags).
|
|
||||||
|
|
||||||
## 4. Lexer (por que esta separado)
|
|
||||||
- Maneja comillas y metacaracteres sin mezclar con ejecucion.
|
|
||||||
- Detecta errores de comillas sin cerrar.
|
|
||||||
- Facilita el parseo posterior.
|
|
||||||
|
|
||||||
## 5. Parser
|
|
||||||
- Convierte tokens en comandos reales.
|
|
||||||
- Cada `TOK_PIPE` crea un nuevo comando.
|
|
||||||
- Redirecciones se guardan en lista separada (`t_redir`).
|
|
||||||
- Valida errores (pipe sin comando, redireccion sin destino).
|
|
||||||
|
|
||||||
## 6. Expansion
|
|
||||||
- `expand_pipeline()` recorre argv y targets de redireccion.
|
|
||||||
- Reglas:
|
|
||||||
- En comilla simple no se expande.
|
|
||||||
- En comilla doble si se expande.
|
|
||||||
- `$?` es el exit status anterior.
|
|
||||||
|
|
||||||
## 7. Redirecciones y heredoc
|
|
||||||
- `apply_redirections()` abre y hace `dup2()`.
|
|
||||||
- `prepare_heredocs()` genera un pipe con el contenido.
|
|
||||||
- Heredoc no se mete en el historial.
|
|
||||||
|
|
||||||
## 8. Ejecucion y pipes
|
|
||||||
- Si hay un solo builtin, se ejecuta en el padre.
|
|
||||||
- Si hay pipeline, todos se forkean.
|
|
||||||
- Se conectan con `pipe()` y `dup2()`.
|
|
||||||
- Se espera a todos, y el exit status es el del ultimo comando.
|
|
||||||
|
|
||||||
## 9. Builtins
|
|
||||||
- Implementados en `src/builtins/builtins.c`.
|
|
||||||
- `echo`, `cd`, `pwd`, `env`, `export`, `unset`, `exit`.
|
|
||||||
- `export` valida identificadores y permite `KEY=VALUE`.
|
|
||||||
|
|
||||||
## 10. Señales
|
|
||||||
- Una sola global: `g_signal`.
|
|
||||||
- `ctrl-C`: limpia linea y muestra prompt.
|
|
||||||
- `ctrl-\`: se ignora en interactivo.
|
|
||||||
- En child se restauran señales por defecto.
|
|
||||||
|
|
||||||
## 11. Ejemplos rapidos para demostrar
|
|
||||||
- Pipes: `ls | wc -l`
|
|
||||||
- Redireccion: `echo hola > out.txt`
|
|
||||||
- Heredoc: `cat << EOF` -> texto -> `EOF`
|
|
||||||
- Expansion: `echo $HOME`, `echo $?`
|
|
||||||
|
|
||||||
## 12. Mensaje final recomendado
|
|
||||||
"Separar lexer, parser, expansion y ejecucion me permitio mantener el codigo claro
|
|
||||||
y replicar el comportamiento de bash para el minimo requerido por el subject."
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# Minishell - Checklist de pruebas manuales
|
|
||||||
|
|
||||||
Ejecuta en `minishell-codex/`:
|
|
||||||
- `make`
|
|
||||||
- `./minishell`
|
|
||||||
|
|
||||||
## 1. Prompt y salida
|
|
||||||
- Iniciar y salir con `ctrl-D`.
|
|
||||||
- `exit` debe cerrar el shell con el ultimo status.
|
|
||||||
|
|
||||||
## 2. Comandos simples
|
|
||||||
- `ls`
|
|
||||||
- `pwd`
|
|
||||||
- `echo hola`
|
|
||||||
|
|
||||||
## 3. Builtins
|
|
||||||
- `echo -n hola` (sin salto de linea)
|
|
||||||
- `cd /` luego `pwd`
|
|
||||||
- `export TEST=42` luego `env | grep TEST`
|
|
||||||
- `unset TEST` luego `env | grep TEST` (no debe aparecer)
|
|
||||||
- `env` sin argumentos
|
|
||||||
- `exit 2`
|
|
||||||
|
|
||||||
## 4. Expansion
|
|
||||||
- `echo $HOME`
|
|
||||||
- `echo $?` despues de un comando que falle (ej: `ls noexiste`)
|
|
||||||
- `echo '$HOME'` (no expande)
|
|
||||||
- `echo "$HOME"` (si expande)
|
|
||||||
|
|
||||||
## 5. Pipes
|
|
||||||
- `ls | wc -l`
|
|
||||||
- `echo hola | cat`
|
|
||||||
- `cat /etc/passwd | grep root | wc -l`
|
|
||||||
|
|
||||||
## 6. Redirecciones
|
|
||||||
- `echo hola > out.txt` y luego `cat out.txt`
|
|
||||||
- `echo 1 >> out.txt` y luego `cat out.txt`
|
|
||||||
- `cat < out.txt`
|
|
||||||
|
|
||||||
## 7. Heredoc
|
|
||||||
- `cat << EOF`
|
|
||||||
- escribir varias lineas
|
|
||||||
- `EOF`
|
|
||||||
- Ver que se imprime todo lo escrito.
|
|
||||||
|
|
||||||
## 8. Comillas
|
|
||||||
- `echo "a b c"` (una sola palabra)
|
|
||||||
- `echo 'a b c'` (una sola palabra)
|
|
||||||
- `echo "a 'b' c"`
|
|
||||||
|
|
||||||
## 9. Errores de parseo
|
|
||||||
- `| ls` (no debe ejecutar)
|
|
||||||
- `echo hola >` (error)
|
|
||||||
- `echo "hola` (comillas sin cerrar)
|
|
||||||
|
|
||||||
## 10. Senales
|
|
||||||
- `ctrl-C` en prompt: debe limpiar linea y mostrar prompt nuevo.
|
|
||||||
- `sleep 5` y `ctrl-C`: debe interrumpir el proceso.
|
|
||||||
- `ctrl-\` no debe imprimir nada en prompt interactivo.
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
#ifndef MINISHELL_H
|
|
||||||
#define MINISHELL_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <readline/readline.h>
|
|
||||||
#include <readline/history.h>
|
|
||||||
|
|
||||||
#define MS_PROMPT "minishell> "
|
|
||||||
|
|
||||||
extern int g_signal;
|
|
||||||
|
|
||||||
typedef enum e_tokentype
|
|
||||||
{
|
|
||||||
TOK_WORD,
|
|
||||||
TOK_PIPE,
|
|
||||||
TOK_REDIR_IN,
|
|
||||||
TOK_REDIR_OUT,
|
|
||||||
TOK_REDIR_APPEND,
|
|
||||||
TOK_HEREDOC
|
|
||||||
} t_tokentype;
|
|
||||||
|
|
||||||
typedef struct s_token
|
|
||||||
{
|
|
||||||
char *text;
|
|
||||||
t_tokentype type;
|
|
||||||
struct s_token *next;
|
|
||||||
} t_token;
|
|
||||||
|
|
||||||
typedef enum e_redirtype
|
|
||||||
{
|
|
||||||
REDIR_IN,
|
|
||||||
REDIR_OUT,
|
|
||||||
REDIR_APPEND,
|
|
||||||
REDIR_HEREDOC
|
|
||||||
} t_redirtype;
|
|
||||||
|
|
||||||
typedef struct s_redir
|
|
||||||
{
|
|
||||||
t_redirtype type;
|
|
||||||
char *target;
|
|
||||||
int fd;
|
|
||||||
struct s_redir *next;
|
|
||||||
} t_redir;
|
|
||||||
|
|
||||||
typedef struct s_command
|
|
||||||
{
|
|
||||||
char **argv;
|
|
||||||
int argc;
|
|
||||||
char *path;
|
|
||||||
t_redir *redirs;
|
|
||||||
} t_command;
|
|
||||||
|
|
||||||
typedef struct s_pipeline
|
|
||||||
{
|
|
||||||
t_command **cmds;
|
|
||||||
size_t count;
|
|
||||||
} t_pipeline;
|
|
||||||
|
|
||||||
typedef struct s_env
|
|
||||||
{
|
|
||||||
char *key;
|
|
||||||
char *value;
|
|
||||||
struct s_env *next;
|
|
||||||
} t_env;
|
|
||||||
|
|
||||||
typedef struct s_shell
|
|
||||||
{
|
|
||||||
t_env *env;
|
|
||||||
int exit_status;
|
|
||||||
int last_status;
|
|
||||||
int exit_requested;
|
|
||||||
int interactive;
|
|
||||||
} t_shell;
|
|
||||||
|
|
||||||
/* core */
|
|
||||||
void ms_init(t_shell *sh, char **envp);
|
|
||||||
void ms_loop(t_shell *sh);
|
|
||||||
void ms_cleanup(t_shell *sh);
|
|
||||||
void ms_setup_signals(t_shell *sh);
|
|
||||||
void ms_set_child_signals(void);
|
|
||||||
void ms_set_heredoc_signals(void);
|
|
||||||
|
|
||||||
/* parser */
|
|
||||||
t_token *lex_line(const char *line, int *error);
|
|
||||||
void free_tokens(t_token *toks);
|
|
||||||
|
|
||||||
t_pipeline *parse_tokens(t_token *toks, int *error);
|
|
||||||
void free_pipeline(t_pipeline *p);
|
|
||||||
|
|
||||||
int expand_pipeline(t_pipeline *p, t_shell *sh);
|
|
||||||
|
|
||||||
/* executor */
|
|
||||||
int execute_pipeline(t_pipeline *p, t_shell *sh);
|
|
||||||
int prepare_heredocs(t_pipeline *p, t_shell *sh);
|
|
||||||
int apply_redirections(t_command *cmd, int *saved_stdin, int *saved_stdout);
|
|
||||||
void restore_redirections(int saved_stdin, int saved_stdout);
|
|
||||||
char *resolve_path(const char *cmd, t_shell *sh);
|
|
||||||
|
|
||||||
/* env */
|
|
||||||
void env_init(t_shell *sh, char **envp);
|
|
||||||
void env_clear(t_shell *sh);
|
|
||||||
char *env_get(t_shell *sh, const char *key);
|
|
||||||
int env_set(t_shell *sh, const char *key, const char *value);
|
|
||||||
int env_unset(t_shell *sh, const char *key);
|
|
||||||
char **env_to_envp(t_shell *sh);
|
|
||||||
void env_free_envp(char **envp);
|
|
||||||
void env_print(t_shell *sh);
|
|
||||||
|
|
||||||
/* builtins */
|
|
||||||
int is_builtin(const char *name);
|
|
||||||
int exec_builtin(t_command *cmd, t_shell *sh);
|
|
||||||
|
|
||||||
/* utils */
|
|
||||||
int ms_is_space(int c);
|
|
||||||
int ms_is_alpha(int c);
|
|
||||||
int ms_is_alnum(int c);
|
|
||||||
int ms_is_digit(int c);
|
|
||||||
char *ms_strdup(const char *s);
|
|
||||||
char *ms_strndup(const char *s, size_t n);
|
|
||||||
char *ms_strjoin(const char *a, const char *b);
|
|
||||||
char *ms_strjoin3(const char *a, const char *b, const char *c);
|
|
||||||
char *ms_substr(const char *s, size_t start, size_t len);
|
|
||||||
char **ms_split(const char *s, char delim);
|
|
||||||
void ms_free_split(char **sp);
|
|
||||||
char *ms_itoa(int n);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,221 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static int builtin_echo(t_command *cmd, t_shell *sh);
|
|
||||||
static int builtin_cd(t_command *cmd, t_shell *sh);
|
|
||||||
static int builtin_pwd(t_command *cmd, t_shell *sh);
|
|
||||||
static int builtin_env(t_command *cmd, t_shell *sh);
|
|
||||||
static int builtin_export(t_command *cmd, t_shell *sh);
|
|
||||||
static int builtin_unset(t_command *cmd, t_shell *sh);
|
|
||||||
static int builtin_exit(t_command *cmd, t_shell *sh);
|
|
||||||
|
|
||||||
int is_builtin(const char *name)
|
|
||||||
{
|
|
||||||
if (!name)
|
|
||||||
return 0;
|
|
||||||
return (strcmp(name, "echo") == 0 || strcmp(name, "cd") == 0
|
|
||||||
|| strcmp(name, "pwd") == 0 || strcmp(name, "env") == 0
|
|
||||||
|| strcmp(name, "export") == 0 || strcmp(name, "unset") == 0
|
|
||||||
|| strcmp(name, "exit") == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int exec_builtin(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
if (strcmp(cmd->argv[0], "echo") == 0)
|
|
||||||
return builtin_echo(cmd, sh);
|
|
||||||
if (strcmp(cmd->argv[0], "cd") == 0)
|
|
||||||
return builtin_cd(cmd, sh);
|
|
||||||
if (strcmp(cmd->argv[0], "pwd") == 0)
|
|
||||||
return builtin_pwd(cmd, sh);
|
|
||||||
if (strcmp(cmd->argv[0], "env") == 0)
|
|
||||||
return builtin_env(cmd, sh);
|
|
||||||
if (strcmp(cmd->argv[0], "export") == 0)
|
|
||||||
return builtin_export(cmd, sh);
|
|
||||||
if (strcmp(cmd->argv[0], "unset") == 0)
|
|
||||||
return builtin_unset(cmd, sh);
|
|
||||||
if (strcmp(cmd->argv[0], "exit") == 0)
|
|
||||||
return builtin_exit(cmd, sh);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int builtin_echo(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
int i = 1;
|
|
||||||
int newline = 1;
|
|
||||||
|
|
||||||
(void)sh;
|
|
||||||
while (cmd->argv[i] && cmd->argv[i][0] == '-' && cmd->argv[i][1] == 'n')
|
|
||||||
{
|
|
||||||
int j = 2;
|
|
||||||
while (cmd->argv[i][j] == 'n')
|
|
||||||
j++;
|
|
||||||
if (cmd->argv[i][j] != '\0')
|
|
||||||
break;
|
|
||||||
newline = 0;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
while (cmd->argv[i])
|
|
||||||
{
|
|
||||||
printf("%s", cmd->argv[i]);
|
|
||||||
if (cmd->argv[i + 1])
|
|
||||||
printf(" ");
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (newline)
|
|
||||||
printf("\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int builtin_pwd(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
char buf[4096];
|
|
||||||
(void)cmd;
|
|
||||||
(void)sh;
|
|
||||||
if (getcwd(buf, sizeof(buf)))
|
|
||||||
printf("%s\n", buf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int builtin_cd(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
char *path;
|
|
||||||
char cwd[4096];
|
|
||||||
|
|
||||||
if (cmd->argc > 2)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "minishell: cd: too many arguments\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (cmd->argc == 1)
|
|
||||||
path = env_get(sh, "HOME");
|
|
||||||
else
|
|
||||||
path = cmd->argv[1];
|
|
||||||
if (!path)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "minishell: cd: HOME not set\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (getcwd(cwd, sizeof(cwd)))
|
|
||||||
env_set(sh, "OLDPWD", cwd);
|
|
||||||
if (chdir(path) != 0)
|
|
||||||
{
|
|
||||||
perror("minishell: cd");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (getcwd(cwd, sizeof(cwd)))
|
|
||||||
env_set(sh, "PWD", cwd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int builtin_env(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
if (cmd->argc > 1)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "minishell: env: too many arguments\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
env_print(sh);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int valid_identifier(const char *s)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
if (!s || !ms_is_alpha((unsigned char)s[0]))
|
|
||||||
return 0;
|
|
||||||
while (s[i])
|
|
||||||
{
|
|
||||||
if (!ms_is_alnum((unsigned char)s[i]))
|
|
||||||
return 0;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int builtin_export(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
int i = 1;
|
|
||||||
if (cmd->argc == 1)
|
|
||||||
{
|
|
||||||
env_print(sh);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
while (cmd->argv[i])
|
|
||||||
{
|
|
||||||
char *eq = strchr(cmd->argv[i], '=');
|
|
||||||
if (eq)
|
|
||||||
{
|
|
||||||
char *key = ms_strndup(cmd->argv[i], (size_t)(eq - cmd->argv[i]));
|
|
||||||
char *val = ms_strdup(eq + 1);
|
|
||||||
if (!valid_identifier(key))
|
|
||||||
fprintf(stderr, "minishell: export: `%s': not a valid identifier\n", cmd->argv[i]);
|
|
||||||
else
|
|
||||||
env_set(sh, key, val);
|
|
||||||
free(key);
|
|
||||||
free(val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!valid_identifier(cmd->argv[i]))
|
|
||||||
fprintf(stderr, "minishell: export: `%s': not a valid identifier\n", cmd->argv[i]);
|
|
||||||
else
|
|
||||||
env_set(sh, cmd->argv[i], "");
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int builtin_unset(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
int i = 1;
|
|
||||||
while (cmd->argv[i])
|
|
||||||
{
|
|
||||||
env_unset(sh, cmd->argv[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int builtin_exit(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
long code = sh->exit_status;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (sh->interactive)
|
|
||||||
printf("exit\n");
|
|
||||||
if (cmd->argc == 1)
|
|
||||||
{
|
|
||||||
sh->exit_requested = 1;
|
|
||||||
sh->exit_status = (int)(code & 0xFF);
|
|
||||||
return sh->exit_status;
|
|
||||||
}
|
|
||||||
if (cmd->argc > 2)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "minishell: exit: too many arguments\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (cmd->argv[1][i] == '+' || cmd->argv[1][i] == '-')
|
|
||||||
i++;
|
|
||||||
if (cmd->argv[1][i] == '\0')
|
|
||||||
{
|
|
||||||
fprintf(stderr, "minishell: exit: %s: numeric argument required\n", cmd->argv[1]);
|
|
||||||
sh->exit_requested = 1;
|
|
||||||
sh->exit_status = 2;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
while (cmd->argv[1][i])
|
|
||||||
{
|
|
||||||
if (!ms_is_digit((unsigned char)cmd->argv[1][i]))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "minishell: exit: %s: numeric argument required\n", cmd->argv[1]);
|
|
||||||
sh->exit_requested = 1;
|
|
||||||
sh->exit_status = 2;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
code = strtol(cmd->argv[1], NULL, 10);
|
|
||||||
sh->exit_requested = 1;
|
|
||||||
sh->exit_status = (int)(code & 0xFF);
|
|
||||||
return sh->exit_status;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
void ms_init(t_shell *sh, char **envp)
|
|
||||||
{
|
|
||||||
memset(sh, 0, sizeof(*sh));
|
|
||||||
sh->interactive = isatty(STDIN_FILENO);
|
|
||||||
sh->exit_status = 0;
|
|
||||||
sh->last_status = 0;
|
|
||||||
sh->exit_requested = 0;
|
|
||||||
env_init(sh, envp);
|
|
||||||
ms_setup_signals(sh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ms_cleanup(t_shell *sh)
|
|
||||||
{
|
|
||||||
env_clear(sh);
|
|
||||||
rl_clear_history();
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static void handle_line(t_shell *sh, char *line)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
t_token *toks = NULL;
|
|
||||||
t_pipeline *p = NULL;
|
|
||||||
|
|
||||||
toks = lex_line(line, &error);
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
free_tokens(toks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p = parse_tokens(toks, &error);
|
|
||||||
free_tokens(toks);
|
|
||||||
if (error || !p)
|
|
||||||
{
|
|
||||||
free_pipeline(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (expand_pipeline(p, sh) != 0)
|
|
||||||
{
|
|
||||||
free_pipeline(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sh->exit_status = execute_pipeline(p, sh);
|
|
||||||
sh->last_status = sh->exit_status;
|
|
||||||
free_pipeline(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ms_loop(t_shell *sh)
|
|
||||||
{
|
|
||||||
char *line;
|
|
||||||
|
|
||||||
while (!sh->exit_requested)
|
|
||||||
{
|
|
||||||
line = readline(MS_PROMPT);
|
|
||||||
if (!line)
|
|
||||||
break;
|
|
||||||
if (line[0] != '\0')
|
|
||||||
add_history(line);
|
|
||||||
handle_line(sh, line);
|
|
||||||
free(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
int g_signal = 0;
|
|
||||||
|
|
||||||
static void sigint_handler(int sig)
|
|
||||||
{
|
|
||||||
g_signal = sig;
|
|
||||||
write(STDOUT_FILENO, "\n", 1);
|
|
||||||
rl_on_new_line();
|
|
||||||
rl_replace_line("", 0);
|
|
||||||
rl_redisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sigquit_handler(int sig)
|
|
||||||
{
|
|
||||||
g_signal = sig;
|
|
||||||
(void)sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ms_setup_signals(t_shell *sh)
|
|
||||||
{
|
|
||||||
struct sigaction sa_int;
|
|
||||||
struct sigaction sa_quit;
|
|
||||||
|
|
||||||
(void)sh;
|
|
||||||
memset(&sa_int, 0, sizeof(sa_int));
|
|
||||||
memset(&sa_quit, 0, sizeof(sa_quit));
|
|
||||||
sa_int.sa_handler = sigint_handler;
|
|
||||||
sa_quit.sa_handler = sigquit_handler;
|
|
||||||
sigemptyset(&sa_int.sa_mask);
|
|
||||||
sigemptyset(&sa_quit.sa_mask);
|
|
||||||
sigaction(SIGINT, &sa_int, NULL);
|
|
||||||
sigaction(SIGQUIT, &sa_quit, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ms_set_child_signals(void)
|
|
||||||
{
|
|
||||||
signal(SIGINT, SIG_DFL);
|
|
||||||
signal(SIGQUIT, SIG_DFL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ms_set_heredoc_signals(void)
|
|
||||||
{
|
|
||||||
signal(SIGINT, SIG_DFL);
|
|
||||||
signal(SIGQUIT, SIG_IGN);
|
|
||||||
}
|
|
||||||
171
minishell-codex/src/env/env.c
vendored
171
minishell-codex/src/env/env.c
vendored
@@ -1,171 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static t_env *env_new(const char *key, const char *value)
|
|
||||||
{
|
|
||||||
t_env *n = (t_env *)calloc(1, sizeof(t_env));
|
|
||||||
if (!n)
|
|
||||||
return NULL;
|
|
||||||
n->key = ms_strdup(key);
|
|
||||||
n->value = value ? ms_strdup(value) : ms_strdup("");
|
|
||||||
if (!n->key || !n->value)
|
|
||||||
{
|
|
||||||
free(n->key);
|
|
||||||
free(n->value);
|
|
||||||
free(n);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void env_init(t_shell *sh, char **envp)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *eq;
|
|
||||||
|
|
||||||
sh->env = NULL;
|
|
||||||
if (!envp)
|
|
||||||
return;
|
|
||||||
i = 0;
|
|
||||||
while (envp[i])
|
|
||||||
{
|
|
||||||
eq = strchr(envp[i], '=');
|
|
||||||
if (eq)
|
|
||||||
{
|
|
||||||
char *key = ms_strndup(envp[i], (size_t)(eq - envp[i]));
|
|
||||||
char *val = ms_strdup(eq + 1);
|
|
||||||
env_set(sh, key, val);
|
|
||||||
free(key);
|
|
||||||
free(val);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void env_clear(t_shell *sh)
|
|
||||||
{
|
|
||||||
t_env *cur = sh->env;
|
|
||||||
t_env *next;
|
|
||||||
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
next = cur->next;
|
|
||||||
free(cur->key);
|
|
||||||
free(cur->value);
|
|
||||||
free(cur);
|
|
||||||
cur = next;
|
|
||||||
}
|
|
||||||
sh->env = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *env_get(t_shell *sh, const char *key)
|
|
||||||
{
|
|
||||||
t_env *cur = sh->env;
|
|
||||||
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
if (strcmp(cur->key, key) == 0)
|
|
||||||
return cur->value;
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int env_set(t_shell *sh, const char *key, const char *value)
|
|
||||||
{
|
|
||||||
t_env *cur = sh->env;
|
|
||||||
t_env *prev = NULL;
|
|
||||||
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
if (strcmp(cur->key, key) == 0)
|
|
||||||
{
|
|
||||||
char *dup = ms_strdup(value ? value : "");
|
|
||||||
if (!dup)
|
|
||||||
return 1;
|
|
||||||
free(cur->value);
|
|
||||||
cur->value = dup;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
prev = cur;
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
cur = env_new(key, value);
|
|
||||||
if (!cur)
|
|
||||||
return 1;
|
|
||||||
if (prev)
|
|
||||||
prev->next = cur;
|
|
||||||
else
|
|
||||||
sh->env = cur;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int env_unset(t_shell *sh, const char *key)
|
|
||||||
{
|
|
||||||
t_env *cur = sh->env;
|
|
||||||
t_env *prev = NULL;
|
|
||||||
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
if (strcmp(cur->key, key) == 0)
|
|
||||||
{
|
|
||||||
if (prev)
|
|
||||||
prev->next = cur->next;
|
|
||||||
else
|
|
||||||
sh->env = cur->next;
|
|
||||||
free(cur->key);
|
|
||||||
free(cur->value);
|
|
||||||
free(cur);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
prev = cur;
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char **env_to_envp(t_shell *sh)
|
|
||||||
{
|
|
||||||
char **envp;
|
|
||||||
int count = 0;
|
|
||||||
t_env *cur = sh->env;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
envp = (char **)calloc((size_t)count + 1, sizeof(char *));
|
|
||||||
if (!envp)
|
|
||||||
return NULL;
|
|
||||||
cur = sh->env;
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
char *kv = ms_strjoin3(cur->key, "=", cur->value);
|
|
||||||
envp[i++] = kv;
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
envp[i] = NULL;
|
|
||||||
return envp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void env_free_envp(char **envp)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
if (!envp)
|
|
||||||
return;
|
|
||||||
while (envp[i])
|
|
||||||
free(envp[i++]);
|
|
||||||
free(envp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void env_print(t_shell *sh)
|
|
||||||
{
|
|
||||||
t_env *cur = sh->env;
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
if (cur->value)
|
|
||||||
printf("%s=%s\n", cur->key, cur->value);
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static int exec_external(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
char **envp = env_to_envp(sh);
|
|
||||||
if (!envp)
|
|
||||||
return 1;
|
|
||||||
execve(cmd->path, cmd->argv, envp);
|
|
||||||
perror(cmd->path);
|
|
||||||
env_free_envp(envp);
|
|
||||||
return 126;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int run_command_child(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
int saved_in, saved_out;
|
|
||||||
|
|
||||||
if (apply_redirections(cmd, &saved_in, &saved_out) != 0)
|
|
||||||
return 1;
|
|
||||||
if (is_builtin(cmd->argv[0]))
|
|
||||||
return exec_builtin(cmd, sh);
|
|
||||||
return exec_external(cmd, sh);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int run_command_parent_builtin(t_command *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
int saved_in, saved_out;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (apply_redirections(cmd, &saved_in, &saved_out) != 0)
|
|
||||||
return 1;
|
|
||||||
status = exec_builtin(cmd, sh);
|
|
||||||
restore_redirections(saved_in, saved_out);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int setup_pipes(int idx, int count, int pipefd[2])
|
|
||||||
{
|
|
||||||
if (idx + 1 >= count)
|
|
||||||
return 0;
|
|
||||||
if (pipe(pipefd) == -1)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_child_fds(int idx, int count, int prev_read, int pipefd[2])
|
|
||||||
{
|
|
||||||
if (prev_read != -1)
|
|
||||||
{
|
|
||||||
dup2(prev_read, STDIN_FILENO);
|
|
||||||
close(prev_read);
|
|
||||||
}
|
|
||||||
if (idx + 1 < count)
|
|
||||||
{
|
|
||||||
dup2(pipefd[1], STDOUT_FILENO);
|
|
||||||
close(pipefd[0]);
|
|
||||||
close(pipefd[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_parent_fds(int idx, int count, int *prev_read, int pipefd[2])
|
|
||||||
{
|
|
||||||
if (*prev_read != -1)
|
|
||||||
close(*prev_read);
|
|
||||||
if (idx + 1 < count)
|
|
||||||
{
|
|
||||||
close(pipefd[1]);
|
|
||||||
*prev_read = pipefd[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*prev_read = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int execute_pipeline(t_pipeline *p, t_shell *sh)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int prev_read = -1;
|
|
||||||
pid_t *pids;
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
if (!p || p->count == 0)
|
|
||||||
return 0;
|
|
||||||
if (prepare_heredocs(p, sh) != 0)
|
|
||||||
return sh->exit_status;
|
|
||||||
for (size_t k = 0; k < p->count; k++)
|
|
||||||
{
|
|
||||||
if (!p->cmds[k]->argv || !p->cmds[k]->argv[0])
|
|
||||||
return 1;
|
|
||||||
free(p->cmds[k]->path);
|
|
||||||
p->cmds[k]->path = resolve_path(p->cmds[k]->argv[0], sh);
|
|
||||||
}
|
|
||||||
if (p->count == 1 && is_builtin(p->cmds[0]->argv[0]))
|
|
||||||
return run_command_parent_builtin(p->cmds[0], sh);
|
|
||||||
pids = (pid_t *)calloc(p->count, sizeof(pid_t));
|
|
||||||
if (!pids)
|
|
||||||
return 1;
|
|
||||||
for (i = 0; i < (int)p->count; i++)
|
|
||||||
{
|
|
||||||
int pipefd[2] = {-1, -1};
|
|
||||||
if (setup_pipes(i, (int)p->count, pipefd))
|
|
||||||
break;
|
|
||||||
pids[i] = fork();
|
|
||||||
if (pids[i] == 0)
|
|
||||||
{
|
|
||||||
ms_set_child_signals();
|
|
||||||
setup_child_fds(i, (int)p->count, prev_read, pipefd);
|
|
||||||
if (!p->cmds[i]->path)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "minishell: %s: command not found\n", p->cmds[i]->argv[0]);
|
|
||||||
exit(127);
|
|
||||||
}
|
|
||||||
status = run_command_child(p->cmds[i], sh);
|
|
||||||
exit(status);
|
|
||||||
}
|
|
||||||
close_parent_fds(i, (int)p->count, &prev_read, pipefd);
|
|
||||||
}
|
|
||||||
for (i = 0; i < (int)p->count; i++)
|
|
||||||
{
|
|
||||||
int wstatus = 0;
|
|
||||||
if (pids[i] > 0)
|
|
||||||
{
|
|
||||||
waitpid(pids[i], &wstatus, 0);
|
|
||||||
if (i == (int)p->count - 1)
|
|
||||||
{
|
|
||||||
if (WIFEXITED(wstatus))
|
|
||||||
status = WEXITSTATUS(wstatus);
|
|
||||||
else if (WIFSIGNALED(wstatus))
|
|
||||||
status = 128 + WTERMSIG(wstatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(pids);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static int has_slash(const char *s)
|
|
||||||
{
|
|
||||||
return (s && strchr(s, '/'));
|
|
||||||
}
|
|
||||||
|
|
||||||
char *resolve_path(const char *cmd, t_shell *sh)
|
|
||||||
{
|
|
||||||
char *path_env;
|
|
||||||
char **parts;
|
|
||||||
char *candidate;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!cmd)
|
|
||||||
return NULL;
|
|
||||||
if (is_builtin(cmd))
|
|
||||||
return ms_strdup(cmd);
|
|
||||||
if (has_slash(cmd))
|
|
||||||
return ms_strdup(cmd);
|
|
||||||
path_env = env_get(sh, "PATH");
|
|
||||||
if (!path_env)
|
|
||||||
return NULL;
|
|
||||||
parts = ms_split(path_env, ':');
|
|
||||||
if (!parts)
|
|
||||||
return NULL;
|
|
||||||
i = 0;
|
|
||||||
while (parts[i])
|
|
||||||
{
|
|
||||||
candidate = ms_strjoin3(parts[i], "/", cmd);
|
|
||||||
if (candidate && access(candidate, X_OK) == 0)
|
|
||||||
{
|
|
||||||
ms_free_split(parts);
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
free(candidate);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
ms_free_split(parts);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static int open_redir(t_redir *r)
|
|
||||||
{
|
|
||||||
if (r->type == REDIR_IN)
|
|
||||||
return open(r->target, O_RDONLY);
|
|
||||||
if (r->type == REDIR_OUT)
|
|
||||||
return open(r->target, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
||||||
if (r->type == REDIR_APPEND)
|
|
||||||
return open(r->target, O_WRONLY | O_CREAT | O_APPEND, 0644);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int prepare_heredocs(t_pipeline *p, t_shell *sh)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
g_signal = 0;
|
|
||||||
for (i = 0; i < p->count; i++)
|
|
||||||
{
|
|
||||||
t_redir *r = p->cmds[i]->redirs;
|
|
||||||
while (r)
|
|
||||||
{
|
|
||||||
if (r->type == REDIR_HEREDOC)
|
|
||||||
{
|
|
||||||
int fds[2];
|
|
||||||
char *line;
|
|
||||||
ms_set_heredoc_signals();
|
|
||||||
if (pipe(fds) == -1)
|
|
||||||
return 1;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
line = readline("> ");
|
|
||||||
if (!line)
|
|
||||||
break;
|
|
||||||
if (strcmp(line, r->target) == 0)
|
|
||||||
{
|
|
||||||
free(line);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
write(fds[1], line, strlen(line));
|
|
||||||
write(fds[1], "\n", 1);
|
|
||||||
free(line);
|
|
||||||
}
|
|
||||||
close(fds[1]);
|
|
||||||
r->fd = fds[0];
|
|
||||||
ms_setup_signals(sh);
|
|
||||||
if (g_signal == SIGINT)
|
|
||||||
{
|
|
||||||
sh->exit_status = 130;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r = r->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int apply_redirections(t_command *cmd, int *saved_stdin, int *saved_stdout)
|
|
||||||
{
|
|
||||||
t_redir *r = cmd->redirs;
|
|
||||||
*saved_stdin = -1;
|
|
||||||
*saved_stdout = -1;
|
|
||||||
while (r)
|
|
||||||
{
|
|
||||||
int fd = -1;
|
|
||||||
if (r->type == REDIR_HEREDOC)
|
|
||||||
fd = r->fd;
|
|
||||||
else
|
|
||||||
fd = open_redir(r);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
perror(r->target);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (r->type == REDIR_IN || r->type == REDIR_HEREDOC)
|
|
||||||
{
|
|
||||||
if (*saved_stdin == -1)
|
|
||||||
*saved_stdin = dup(STDIN_FILENO);
|
|
||||||
dup2(fd, STDIN_FILENO);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (*saved_stdout == -1)
|
|
||||||
*saved_stdout = dup(STDOUT_FILENO);
|
|
||||||
dup2(fd, STDOUT_FILENO);
|
|
||||||
}
|
|
||||||
if (r->type != REDIR_HEREDOC)
|
|
||||||
close(fd);
|
|
||||||
r = r->next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void restore_redirections(int saved_stdin, int saved_stdout)
|
|
||||||
{
|
|
||||||
if (saved_stdin != -1)
|
|
||||||
{
|
|
||||||
dup2(saved_stdin, STDIN_FILENO);
|
|
||||||
close(saved_stdin);
|
|
||||||
}
|
|
||||||
if (saved_stdout != -1)
|
|
||||||
{
|
|
||||||
dup2(saved_stdout, STDOUT_FILENO);
|
|
||||||
close(saved_stdout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
int main(int argc, char **argv, char **envp)
|
|
||||||
{
|
|
||||||
t_shell sh;
|
|
||||||
|
|
||||||
(void)argv;
|
|
||||||
if (argc != 1)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Usage: ./minishell\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
ms_init(&sh, envp);
|
|
||||||
ms_loop(&sh);
|
|
||||||
ms_cleanup(&sh);
|
|
||||||
return sh.exit_status;
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static void buf_append(char **buf, size_t *len, size_t *cap, const char *s)
|
|
||||||
{
|
|
||||||
size_t slen;
|
|
||||||
char *newbuf;
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return;
|
|
||||||
slen = strlen(s);
|
|
||||||
if (*len + slen + 1 > *cap)
|
|
||||||
{
|
|
||||||
*cap = (*len + slen + 1) * 2;
|
|
||||||
newbuf = (char *)realloc(*buf, *cap);
|
|
||||||
if (!newbuf)
|
|
||||||
return;
|
|
||||||
*buf = newbuf;
|
|
||||||
}
|
|
||||||
memcpy(*buf + *len, s, slen);
|
|
||||||
*len += slen;
|
|
||||||
(*buf)[*len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void buf_append_char(char **buf, size_t *len, size_t *cap, char c)
|
|
||||||
{
|
|
||||||
char tmp[2];
|
|
||||||
tmp[0] = c;
|
|
||||||
tmp[1] = '\0';
|
|
||||||
buf_append(buf, len, cap, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *expand_word(const char *word, t_shell *sh)
|
|
||||||
{
|
|
||||||
int in_single = 0;
|
|
||||||
int in_double = 0;
|
|
||||||
size_t i = 0;
|
|
||||||
char *out = NULL;
|
|
||||||
size_t len = 0, cap = 0;
|
|
||||||
|
|
||||||
while (word && word[i])
|
|
||||||
{
|
|
||||||
if (word[i] == '\'' && !in_double)
|
|
||||||
{
|
|
||||||
in_single = !in_single;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (word[i] == '"' && !in_single)
|
|
||||||
{
|
|
||||||
in_double = !in_double;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (word[i] == '$' && !in_single)
|
|
||||||
{
|
|
||||||
if (word[i + 1] == '?')
|
|
||||||
{
|
|
||||||
char *v = ms_itoa(sh->last_status);
|
|
||||||
buf_append(&out, &len, &cap, v);
|
|
||||||
free(v);
|
|
||||||
i += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ms_is_alpha((unsigned char)word[i + 1]))
|
|
||||||
{
|
|
||||||
size_t j = i + 1;
|
|
||||||
while (word[j] && ms_is_alnum((unsigned char)word[j]))
|
|
||||||
j++;
|
|
||||||
char *name = ms_strndup(word + i + 1, j - (i + 1));
|
|
||||||
char *val = env_get(sh, name);
|
|
||||||
buf_append(&out, &len, &cap, val ? val : "");
|
|
||||||
free(name);
|
|
||||||
i = j;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf_append_char(&out, &len, &cap, word[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (!out)
|
|
||||||
out = ms_strdup("");
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
int expand_pipeline(t_pipeline *p, t_shell *sh)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
int j;
|
|
||||||
for (i = 0; i < p->count; i++)
|
|
||||||
{
|
|
||||||
for (j = 0; p->cmds[i]->argv && p->cmds[i]->argv[j]; j++)
|
|
||||||
{
|
|
||||||
char *neww = expand_word(p->cmds[i]->argv[j], sh);
|
|
||||||
free(p->cmds[i]->argv[j]);
|
|
||||||
p->cmds[i]->argv[j] = neww;
|
|
||||||
}
|
|
||||||
if (p->cmds[i]->redirs)
|
|
||||||
{
|
|
||||||
t_redir *r = p->cmds[i]->redirs;
|
|
||||||
while (r)
|
|
||||||
{
|
|
||||||
if (r->target)
|
|
||||||
{
|
|
||||||
char *nt = expand_word(r->target, sh);
|
|
||||||
free(r->target);
|
|
||||||
r->target = nt;
|
|
||||||
}
|
|
||||||
r = r->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static t_token *token_new(t_tokentype type, const char *text, size_t len)
|
|
||||||
{
|
|
||||||
t_token *t = (t_token *)calloc(1, sizeof(t_token));
|
|
||||||
if (!t)
|
|
||||||
return NULL;
|
|
||||||
t->type = type;
|
|
||||||
if (text)
|
|
||||||
t->text = ms_strndup(text, len);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void token_add(t_token **head, t_token *new)
|
|
||||||
{
|
|
||||||
t_token *cur;
|
|
||||||
if (!new)
|
|
||||||
return;
|
|
||||||
if (!*head)
|
|
||||||
{
|
|
||||||
*head = new;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cur = *head;
|
|
||||||
while (cur->next)
|
|
||||||
cur = cur->next;
|
|
||||||
cur->next = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_tokens(t_token *toks)
|
|
||||||
{
|
|
||||||
t_token *n;
|
|
||||||
while (toks)
|
|
||||||
{
|
|
||||||
n = toks->next;
|
|
||||||
free(toks->text);
|
|
||||||
free(toks);
|
|
||||||
toks = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int is_meta(char c)
|
|
||||||
{
|
|
||||||
return (c == '|' || c == '<' || c == '>');
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_word(const char *line, size_t *i, t_token **out)
|
|
||||||
{
|
|
||||||
size_t start = *i;
|
|
||||||
int in_single = 0;
|
|
||||||
int in_double = 0;
|
|
||||||
|
|
||||||
while (line[*i])
|
|
||||||
{
|
|
||||||
if (line[*i] == '\'' && !in_double)
|
|
||||||
in_single = !in_single;
|
|
||||||
else if (line[*i] == '"' && !in_single)
|
|
||||||
in_double = !in_double;
|
|
||||||
else if (!in_single && !in_double)
|
|
||||||
{
|
|
||||||
if (ms_is_space(line[*i]) || is_meta(line[*i]))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
(*i)++;
|
|
||||||
}
|
|
||||||
if (in_single || in_double)
|
|
||||||
return 1;
|
|
||||||
*out = token_new(TOK_WORD, line + start, *i - start);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
t_token *lex_line(const char *line, int *error)
|
|
||||||
{
|
|
||||||
t_token *toks = NULL;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
*error = 0;
|
|
||||||
while (line[i])
|
|
||||||
{
|
|
||||||
if (ms_is_space(line[i]))
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == '|')
|
|
||||||
{
|
|
||||||
token_add(&toks, token_new(TOK_PIPE, "|", 1));
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == '<')
|
|
||||||
{
|
|
||||||
if (line[i + 1] == '<')
|
|
||||||
{
|
|
||||||
token_add(&toks, token_new(TOK_HEREDOC, "<<", 2));
|
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
token_add(&toks, token_new(TOK_REDIR_IN, "<", 1));
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == '>')
|
|
||||||
{
|
|
||||||
if (line[i + 1] == '>')
|
|
||||||
{
|
|
||||||
token_add(&toks, token_new(TOK_REDIR_APPEND, ">>", 2));
|
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
token_add(&toks, token_new(TOK_REDIR_OUT, ">", 1));
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
t_token *w = NULL;
|
|
||||||
if (read_word(line, &i, &w))
|
|
||||||
{
|
|
||||||
*error = 1;
|
|
||||||
free_tokens(toks);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
token_add(&toks, w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return toks;
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static t_command *command_new(void)
|
|
||||||
{
|
|
||||||
t_command *cmd = (t_command *)calloc(1, sizeof(t_command));
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void command_add_arg(t_command *cmd, const char *text)
|
|
||||||
{
|
|
||||||
char **new_argv;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!cmd || !text)
|
|
||||||
return;
|
|
||||||
i = cmd->argc;
|
|
||||||
new_argv = (char **)calloc((size_t)i + 2, sizeof(char *));
|
|
||||||
if (!new_argv)
|
|
||||||
return;
|
|
||||||
for (int j = 0; j < i; j++)
|
|
||||||
new_argv[j] = cmd->argv[j];
|
|
||||||
new_argv[i] = ms_strdup(text);
|
|
||||||
new_argv[i + 1] = NULL;
|
|
||||||
free(cmd->argv);
|
|
||||||
cmd->argv = new_argv;
|
|
||||||
cmd->argc += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void command_add_redir(t_command *cmd, t_redirtype type, const char *target)
|
|
||||||
{
|
|
||||||
t_redir *r = (t_redir *)calloc(1, sizeof(t_redir));
|
|
||||||
t_redir *cur;
|
|
||||||
if (!r)
|
|
||||||
return;
|
|
||||||
r->type = type;
|
|
||||||
r->target = ms_strdup(target);
|
|
||||||
r->fd = -1;
|
|
||||||
r->next = NULL;
|
|
||||||
if (!cmd->redirs)
|
|
||||||
{
|
|
||||||
cmd->redirs = r;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cur = cmd->redirs;
|
|
||||||
while (cur->next)
|
|
||||||
cur = cur->next;
|
|
||||||
cur->next = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_redirs(t_redir *r)
|
|
||||||
{
|
|
||||||
t_redir *n;
|
|
||||||
while (r)
|
|
||||||
{
|
|
||||||
n = r->next;
|
|
||||||
if (r->fd != -1)
|
|
||||||
close(r->fd);
|
|
||||||
free(r->target);
|
|
||||||
free(r);
|
|
||||||
r = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_pipeline(t_pipeline *p)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
if (!p)
|
|
||||||
return;
|
|
||||||
for (i = 0; i < p->count; i++)
|
|
||||||
{
|
|
||||||
if (p->cmds[i])
|
|
||||||
{
|
|
||||||
for (int j = 0; p->cmds[i]->argv && p->cmds[i]->argv[j]; j++)
|
|
||||||
free(p->cmds[i]->argv[j]);
|
|
||||||
free(p->cmds[i]->argv);
|
|
||||||
free(p->cmds[i]->path);
|
|
||||||
free_redirs(p->cmds[i]->redirs);
|
|
||||||
free(p->cmds[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(p->cmds);
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pipeline_add_cmd(t_pipeline *p, t_command *cmd)
|
|
||||||
{
|
|
||||||
t_command **new_cmds;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
new_cmds = (t_command **)calloc(p->count + 1, sizeof(t_command *));
|
|
||||||
if (!new_cmds)
|
|
||||||
return 1;
|
|
||||||
for (i = 0; i < p->count; i++)
|
|
||||||
new_cmds[i] = p->cmds[i];
|
|
||||||
new_cmds[p->count] = cmd;
|
|
||||||
free(p->cmds);
|
|
||||||
p->cmds = new_cmds;
|
|
||||||
p->count += 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
t_pipeline *parse_tokens(t_token *toks, int *error)
|
|
||||||
{
|
|
||||||
t_pipeline *p;
|
|
||||||
t_command *cmd;
|
|
||||||
t_token *cur;
|
|
||||||
|
|
||||||
*error = 0;
|
|
||||||
p = (t_pipeline *)calloc(1, sizeof(t_pipeline));
|
|
||||||
if (!p)
|
|
||||||
return NULL;
|
|
||||||
cmd = command_new();
|
|
||||||
if (!cmd)
|
|
||||||
{
|
|
||||||
free(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
cur = toks;
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
if (cur->type == TOK_PIPE)
|
|
||||||
{
|
|
||||||
if (cmd->argc == 0)
|
|
||||||
{
|
|
||||||
*error = 1;
|
|
||||||
free_pipeline(p);
|
|
||||||
free(cmd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
pipeline_add_cmd(p, cmd);
|
|
||||||
cmd = command_new();
|
|
||||||
if (!cmd)
|
|
||||||
{
|
|
||||||
*error = 1;
|
|
||||||
free_pipeline(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
cur = cur->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (cur->type == TOK_REDIR_IN || cur->type == TOK_REDIR_OUT
|
|
||||||
|| cur->type == TOK_REDIR_APPEND || cur->type == TOK_HEREDOC)
|
|
||||||
{
|
|
||||||
if (!cur->next || cur->next->type != TOK_WORD)
|
|
||||||
{
|
|
||||||
*error = 1;
|
|
||||||
free_pipeline(p);
|
|
||||||
free(cmd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (cur->type == TOK_REDIR_IN)
|
|
||||||
command_add_redir(cmd, REDIR_IN, cur->next->text);
|
|
||||||
else if (cur->type == TOK_REDIR_OUT)
|
|
||||||
command_add_redir(cmd, REDIR_OUT, cur->next->text);
|
|
||||||
else if (cur->type == TOK_REDIR_APPEND)
|
|
||||||
command_add_redir(cmd, REDIR_APPEND, cur->next->text);
|
|
||||||
else if (cur->type == TOK_HEREDOC)
|
|
||||||
command_add_redir(cmd, REDIR_HEREDOC, cur->next->text);
|
|
||||||
cur = cur->next->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (cur->type == TOK_WORD)
|
|
||||||
command_add_arg(cmd, cur->text);
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
if (cmd->argc == 0)
|
|
||||||
{
|
|
||||||
*error = 1;
|
|
||||||
free_pipeline(p);
|
|
||||||
free(cmd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
pipeline_add_cmd(p, cmd);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
int ms_is_space(int c) { return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f'); }
|
|
||||||
int ms_is_alpha(int c) { return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'); }
|
|
||||||
int ms_is_digit(int c) { return (c >= '0' && c <= '9'); }
|
|
||||||
int ms_is_alnum(int c) { return (ms_is_alpha(c) || ms_is_digit(c)); }
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
static size_t count_parts(const char *s, char delim)
|
|
||||||
{
|
|
||||||
size_t count = 0;
|
|
||||||
int in = 0;
|
|
||||||
while (*s)
|
|
||||||
{
|
|
||||||
if (*s == delim)
|
|
||||||
in = 0;
|
|
||||||
else if (!in)
|
|
||||||
{
|
|
||||||
in = 1;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
char **ms_split(const char *s, char delim)
|
|
||||||
{
|
|
||||||
char **out;
|
|
||||||
size_t parts;
|
|
||||||
size_t i = 0;
|
|
||||||
size_t start = 0;
|
|
||||||
size_t len = 0;
|
|
||||||
int in = 0;
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
parts = count_parts(s, delim);
|
|
||||||
out = (char **)calloc(parts + 1, sizeof(char *));
|
|
||||||
if (!out)
|
|
||||||
return NULL;
|
|
||||||
while (s[i])
|
|
||||||
{
|
|
||||||
if (s[i] == delim)
|
|
||||||
{
|
|
||||||
if (in)
|
|
||||||
{
|
|
||||||
out[len++] = ms_strndup(s + start, i - start);
|
|
||||||
in = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!in)
|
|
||||||
{
|
|
||||||
in = 1;
|
|
||||||
start = i;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (in)
|
|
||||||
out[len++] = ms_strndup(s + start, i - start);
|
|
||||||
out[len] = NULL;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ms_free_split(char **sp)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
if (!sp)
|
|
||||||
return;
|
|
||||||
while (sp[i])
|
|
||||||
free(sp[i++]);
|
|
||||||
free(sp);
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
#include "minishell.h"
|
|
||||||
|
|
||||||
char *ms_strdup(const char *s)
|
|
||||||
{
|
|
||||||
char *out;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
len = strlen(s);
|
|
||||||
out = (char *)malloc(len + 1);
|
|
||||||
if (!out)
|
|
||||||
return NULL;
|
|
||||||
memcpy(out, s, len);
|
|
||||||
out[len] = '\0';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ms_strndup(const char *s, size_t n)
|
|
||||||
{
|
|
||||||
char *out;
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
out = (char *)malloc(n + 1);
|
|
||||||
if (!out)
|
|
||||||
return NULL;
|
|
||||||
memcpy(out, s, n);
|
|
||||||
out[n] = '\0';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ms_substr(const char *s, size_t start, size_t len)
|
|
||||||
{
|
|
||||||
size_t slen;
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
slen = strlen(s);
|
|
||||||
if (start >= slen)
|
|
||||||
return ms_strdup("");
|
|
||||||
if (start + len > slen)
|
|
||||||
len = slen - start;
|
|
||||||
return ms_strndup(s + start, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ms_strjoin(const char *a, const char *b)
|
|
||||||
{
|
|
||||||
size_t la;
|
|
||||||
size_t lb;
|
|
||||||
char *out;
|
|
||||||
|
|
||||||
if (!a || !b)
|
|
||||||
return NULL;
|
|
||||||
la = strlen(a);
|
|
||||||
lb = strlen(b);
|
|
||||||
out = (char *)malloc(la + lb + 1);
|
|
||||||
if (!out)
|
|
||||||
return NULL;
|
|
||||||
memcpy(out, a, la);
|
|
||||||
memcpy(out + la, b, lb);
|
|
||||||
out[la + lb] = '\0';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ms_strjoin3(const char *a, const char *b, const char *c)
|
|
||||||
{
|
|
||||||
char *ab;
|
|
||||||
char *abc;
|
|
||||||
|
|
||||||
ab = ms_strjoin(a, b);
|
|
||||||
if (!ab)
|
|
||||||
return NULL;
|
|
||||||
abc = ms_strjoin(ab, c);
|
|
||||||
free(ab);
|
|
||||||
return abc;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ms_itoa(int n)
|
|
||||||
{
|
|
||||||
char buf[32];
|
|
||||||
int i;
|
|
||||||
int neg;
|
|
||||||
long nb;
|
|
||||||
|
|
||||||
nb = n;
|
|
||||||
neg = (nb < 0);
|
|
||||||
if (neg)
|
|
||||||
nb = -nb;
|
|
||||||
i = 30;
|
|
||||||
buf[31] = '\0';
|
|
||||||
if (nb == 0)
|
|
||||||
buf[i--] = '0';
|
|
||||||
while (nb > 0)
|
|
||||||
{
|
|
||||||
buf[i--] = (char)('0' + (nb % 10));
|
|
||||||
nb /= 10;
|
|
||||||
}
|
|
||||||
if (neg)
|
|
||||||
buf[i--] = '-';
|
|
||||||
return ms_strdup(&buf[i + 1]);
|
|
||||||
}
|
|
||||||
@@ -11,98 +11,45 @@
|
|||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
#include "builtins.h"
|
#include "builtins.h"
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
static uint8_t get_uint8_from_num(const char *arg, uint8_t *status);
|
static bool exit_arg_is_invalid(const char *arg)
|
||||||
static uint8_t has_overflow(
|
{
|
||||||
uint64_t n,
|
if (arg == NULL)
|
||||||
char digit,
|
return (true);
|
||||||
uint64_t limit
|
if ((*arg == '+' || *arg == '-') && arg[1] == '\0')
|
||||||
);
|
return (true);
|
||||||
static uint8_t resolve_exit_status(
|
if (!ft_strisnum(arg))
|
||||||
t_command cmd,
|
return (true);
|
||||||
t_minishell *msh,
|
return (false);
|
||||||
uint8_t *exit_status
|
}
|
||||||
);
|
|
||||||
|
|
||||||
uint8_t builtin_exit(
|
uint8_t builtin_exit(
|
||||||
t_command cmd,
|
t_command cmd,
|
||||||
t_minishell *msh
|
t_minishell *msh
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
uint8_t exit_status;
|
|
||||||
|
|
||||||
if (isatty(STDIN_FILENO))
|
if (isatty(STDIN_FILENO))
|
||||||
ft_eputendl("exit");
|
ft_eputendl("exit");
|
||||||
if (!resolve_exit_status(cmd, msh, &exit_status))
|
|
||||||
return (msh->exit_status);
|
|
||||||
msh->exit = true;
|
|
||||||
msh->exit_status = exit_status;
|
|
||||||
return (exit_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t resolve_exit_status(
|
|
||||||
t_command cmd,
|
|
||||||
t_minishell *msh,
|
|
||||||
uint8_t *exit_status
|
|
||||||
){
|
|
||||||
if (cmd.argc == 1)
|
if (cmd.argc == 1)
|
||||||
*exit_status = msh->exit_status;
|
{
|
||||||
else if (!get_uint8_from_num(cmd.argv[1], exit_status))
|
msh->exit = 1;
|
||||||
|
return (msh->exit_status);
|
||||||
|
}
|
||||||
|
if (exit_arg_is_invalid(cmd.argv[1]))
|
||||||
{
|
{
|
||||||
ft_eprintf("minishell: exit: %s: numeric argument required\n",
|
ft_eprintf("minishell: exit: %s: numeric argument required\n",
|
||||||
cmd.argv[1]);
|
cmd.argv[1]);
|
||||||
msh->exit = true;
|
msh->exit = 1;
|
||||||
msh->exit_status = 2;
|
msh->exit_status = 2;
|
||||||
return (0);
|
return (msh->exit_status);
|
||||||
}
|
}
|
||||||
else if (cmd.argc > 2)
|
if (cmd.argc > 2)
|
||||||
{
|
{
|
||||||
ft_eputendl("minishell: exit: too many arguments");
|
ft_eputendl("minishell: exit: too many arguments");
|
||||||
msh->exit_status = EXIT_FAILURE;
|
msh->exit_status = EXIT_FAILURE;
|
||||||
return (0);
|
return (msh->exit_status);
|
||||||
}
|
}
|
||||||
return (1);
|
msh->exit = 1;
|
||||||
}
|
msh->exit_status = (uint8_t)ft_atol(cmd.argv[1]);
|
||||||
|
return (msh->exit_status);
|
||||||
static uint8_t get_uint8_from_num(
|
|
||||||
const char *arg,
|
|
||||||
uint8_t *status
|
|
||||||
){
|
|
||||||
uint64_t n;
|
|
||||||
uint64_t limit;
|
|
||||||
int sign;
|
|
||||||
|
|
||||||
if (arg == NULL || *arg == '\0')
|
|
||||||
return (0);
|
|
||||||
n = 0;
|
|
||||||
sign = 1;
|
|
||||||
if (*arg == '+' || *arg == '-')
|
|
||||||
if (*arg++ == '-')
|
|
||||||
sign = -1;
|
|
||||||
if (*arg == '\0')
|
|
||||||
return (0);
|
|
||||||
limit = LONG_MAX;
|
|
||||||
if (sign == -1)
|
|
||||||
limit = (uint64_t)LONG_MAX + 1;
|
|
||||||
while (*arg != '\0')
|
|
||||||
{
|
|
||||||
if (!ft_isdigit(*arg) || has_overflow(n, *arg, limit))
|
|
||||||
return (0);
|
|
||||||
n = (n * 10) + (*arg++ - '0');
|
|
||||||
}
|
|
||||||
*status = (uint8_t)(n * sign);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t has_overflow(
|
|
||||||
uint64_t n,
|
|
||||||
char digit,
|
|
||||||
uint64_t limit
|
|
||||||
){
|
|
||||||
if (n > (limit / 10))
|
|
||||||
return (1);
|
|
||||||
if (n == (limit / 10) && (uint64_t)(digit - '0') > (limit % 10))
|
|
||||||
return (1);
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2026/02/09 22:05:00 by codex #+# #+# */
|
/* Created: 2026/02/09 22:05:00 by codex #+# #+# */
|
||||||
/* Updated: 2026/02/09 22:05:00 by codex ### ########.fr */
|
/* Updated: 2026/02/14 02:02:14 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@@ -71,9 +71,9 @@ static uint8_t export_one(
|
|||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return (EXIT_FAILURE);
|
return (EXIT_FAILURE);
|
||||||
if (eq_pos != NULL)
|
if (eq_pos != NULL)
|
||||||
set_env(name, eq_pos + 1, msh);
|
set_var(name, eq_pos + 1, msh);
|
||||||
else
|
else
|
||||||
set_env(name, "", msh);
|
set_var(name, "", msh);
|
||||||
free(name);
|
free(name);
|
||||||
return (EXIT_SUCCESS);
|
return (EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,4 +9,3 @@
|
|||||||
/* Updated: 2026/02/09 18:40:04 by sede-san ### ########.fr */
|
/* Updated: 2026/02/09 18:40:04 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
|||||||
@@ -28,4 +28,4 @@ void syntax_error_unexpected_token(
|
|||||||
void malloc_error(void)
|
void malloc_error(void)
|
||||||
{
|
{
|
||||||
ft_eprintf("minishell: %s\n", strerror(ENOMEM));
|
ft_eprintf("minishell: %s\n", strerror(ENOMEM));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2026/02/11 00:00:00 by sede-san #+# #+# */
|
/* Created: 2026/02/11 00:00:00 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/11 00:00:00 by sede-san ### ########.fr */
|
/* Updated: 2026/02/14 01:34:37 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@@ -40,9 +40,13 @@ static void handle_execve_error(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
uint8_t exit_status;
|
uint8_t exit_status;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
exit_status = resolve_execve_status();
|
exit_status = resolve_execve_status();
|
||||||
free_envp(envp);
|
i = 0;
|
||||||
|
while (envp[i] != NULL)
|
||||||
|
free(envp[i++]);
|
||||||
|
free(envp);
|
||||||
perror(command->path);
|
perror(command->path);
|
||||||
exit(exit_status);
|
exit(exit_status);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,12 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2026/02/11 00:00:00 by sede-san #+# #+# */
|
/* Created: 2026/02/11 00:00:00 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/11 00:00:00 by sede-san ### ########.fr */
|
/* Updated: 2026/02/14 01:17:01 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
#include "executor.h"
|
#include "executor.h"
|
||||||
|
#include "variables.h"
|
||||||
|
|
||||||
static bool is_path_explicit(
|
static bool is_path_explicit(
|
||||||
const char *command_name
|
const char *command_name
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/10/20 20:51:33 by sede-san #+# #+# */
|
/* Created: 2025/10/20 20:51:33 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/13 20:12:07 by sede-san ### ########.fr */
|
/* Updated: 2026/02/14 01:58:39 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@@ -15,44 +15,14 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "executor.h"
|
#include "executor.h"
|
||||||
|
|
||||||
static void handle_sigint_status(
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (!minishell_consume_sigint())
|
|
||||||
return ;
|
|
||||||
minishell->exit_status = 130;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool handle_eof(
|
|
||||||
char *line,
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (line != NULL)
|
|
||||||
return (false);
|
|
||||||
if (isatty(STDIN_FILENO))
|
|
||||||
ft_putendl("exit");
|
|
||||||
minishell->exit = true;
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_prompts(
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
minishell->prompt.ps1 = DEFAULT_PS1;
|
|
||||||
minishell->prompt.ps2 = DEFAULT_PS2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void minishell_init(
|
void minishell_init(
|
||||||
t_minishell *minishell,
|
t_minishell *minishell,
|
||||||
char **envp
|
char **envp
|
||||||
){
|
){
|
||||||
ft_bzero(minishell, sizeof(t_minishell));
|
ft_bzero(minishell, sizeof(t_minishell));
|
||||||
|
set_intp(minishell);
|
||||||
set_envp(envp, minishell);
|
set_envp(envp, minishell);
|
||||||
set_builtins(minishell);
|
set_builtins(minishell);
|
||||||
set_prompts(minishell);
|
|
||||||
if (minishell->variables.environment == NULL || minishell->builtins == NULL)
|
if (minishell->variables.environment == NULL || minishell->builtins == NULL)
|
||||||
minishell_clear(minishell);
|
minishell_clear(minishell);
|
||||||
}
|
}
|
||||||
@@ -69,7 +39,7 @@ void minishell_run(
|
|||||||
while (!minishell->exit)
|
while (!minishell->exit)
|
||||||
{
|
{
|
||||||
if (isatty(STDIN_FILENO))
|
if (isatty(STDIN_FILENO))
|
||||||
line = readline(minishell->prompt.ps1);
|
line = readline(DEFAULT_PS1);
|
||||||
else
|
else
|
||||||
line = get_next_line(STDIN_FILENO);
|
line = get_next_line(STDIN_FILENO);
|
||||||
handle_sigint_status(minishell);
|
handle_sigint_status(minishell);
|
||||||
@@ -89,6 +59,8 @@ void minishell_clear(
|
|||||||
t_minishell *minishell
|
t_minishell *minishell
|
||||||
){
|
){
|
||||||
rl_clear_history();
|
rl_clear_history();
|
||||||
|
if (minishell->variables.internal != NULL)
|
||||||
|
ft_hashmap_clear(&minishell->variables.internal, free);
|
||||||
if (minishell->variables.environment != NULL)
|
if (minishell->variables.environment != NULL)
|
||||||
ft_hashmap_clear(&minishell->variables.environment, free);
|
ft_hashmap_clear(&minishell->variables.environment, free);
|
||||||
if (minishell->builtins != NULL)
|
if (minishell->builtins != NULL)
|
||||||
|
|||||||
36
src/minishell_helpers.c
Normal file
36
src/minishell_helpers.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* minishell_helpers.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:09:23 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:09:23 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "minishell.h"
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
void handle_sigint_status(
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!minishell_consume_sigint())
|
||||||
|
return ;
|
||||||
|
minishell->exit_status = 130;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_eof(
|
||||||
|
char *line,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (line != NULL)
|
||||||
|
return (false);
|
||||||
|
if (isatty(STDIN_FILENO))
|
||||||
|
ft_putendl("exit");
|
||||||
|
minishell->exit = true;
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
@@ -13,26 +13,20 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
static t_token *tokenize(const char *line, size_t *start);
|
static t_token *tokenize(const char *line, size_t *start);
|
||||||
static t_token_type get_token_type(const char *str);
|
|
||||||
static t_token *token_new(t_token_type type, char *text);
|
|
||||||
void token_clear(t_token *token);
|
|
||||||
static t_token *read_token(t_token_type type, const char *line, size_t *i);
|
|
||||||
static t_token *read_word(const char *line, size_t *i);
|
|
||||||
static inline bool is_meta(char c);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts a command line string into a list of tokens.
|
* @brief Converts a command line string into a list of tokens.
|
||||||
*
|
*
|
||||||
* @return A list of tokens or NULL on error.
|
* @return A list of tokens or NULL on error.
|
||||||
*/
|
*/
|
||||||
t_list *lex(
|
t_list *lex(
|
||||||
const char *line
|
const char *line
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
t_list *tokens;
|
t_list *tokens;
|
||||||
t_token *token;
|
t_token *token;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
tokens = NULL;
|
tokens = NULL;
|
||||||
i = 0;
|
i = 0;
|
||||||
@@ -56,13 +50,13 @@ t_list *lex(
|
|||||||
/**
|
/**
|
||||||
* @return A new token or NULL on error.
|
* @return A new token or NULL on error.
|
||||||
*/
|
*/
|
||||||
static t_token *tokenize(
|
static t_token *tokenize(
|
||||||
const char *line,
|
const char *line,
|
||||||
size_t *start
|
size_t *start
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
t_token *token;
|
t_token *token;
|
||||||
t_token_type type;
|
t_token_type type;
|
||||||
|
|
||||||
if (line == NULL || line[*start] == '\0')
|
if (line == NULL || line[*start] == '\0')
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -73,106 +67,3 @@ static t_token *tokenize(
|
|||||||
token = read_word(line, start);
|
token = read_word(line, start);
|
||||||
return (token);
|
return (token);
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_token_type get_token_type(
|
|
||||||
const char *str
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (str == NULL || str[0] == '\0')
|
|
||||||
return (TOKEN_WORD);
|
|
||||||
if (str[0] == '|')
|
|
||||||
return (TOKEN_PIPE);
|
|
||||||
if (str[0] == '<')
|
|
||||||
{
|
|
||||||
if (str[1] == '<')
|
|
||||||
return (TOKEN_HEREDOC);
|
|
||||||
return (TOKEN_REDIRECT_IN);
|
|
||||||
}
|
|
||||||
if (str[0] == '>')
|
|
||||||
{
|
|
||||||
if (str[1] == '>')
|
|
||||||
return (TOKEN_APPEND);
|
|
||||||
return (TOKEN_REDIRECT_OUT);
|
|
||||||
}
|
|
||||||
return (TOKEN_WORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static t_token *token_new(
|
|
||||||
t_token_type type,
|
|
||||||
char *text
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_token *token;
|
|
||||||
|
|
||||||
token = (t_token *)malloc(sizeof(t_token));
|
|
||||||
if (token == NULL)
|
|
||||||
return (NULL);
|
|
||||||
token->type = type;
|
|
||||||
token->value = text;
|
|
||||||
if (token->type == TOKEN_WORD && token->value == NULL)
|
|
||||||
{
|
|
||||||
free(token);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
return (token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void token_clear(
|
|
||||||
t_token *token
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (token != NULL)
|
|
||||||
{
|
|
||||||
free(token->value);
|
|
||||||
free(token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static t_token *read_token(
|
|
||||||
t_token_type type,
|
|
||||||
const char *line,
|
|
||||||
size_t *i
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const size_t start = *i;
|
|
||||||
size_t end;
|
|
||||||
|
|
||||||
while (is_meta(line[*i]))
|
|
||||||
(*i)++;
|
|
||||||
end = *i;
|
|
||||||
while (ft_isspace(line[*i]))
|
|
||||||
(*i)++;
|
|
||||||
return (token_new(type, ft_substr(line, start, end - start)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static t_token *read_word(
|
|
||||||
const char *line,
|
|
||||||
size_t *i
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const size_t start = *i;
|
|
||||||
bool in_single_quote;
|
|
||||||
bool in_double_quote;
|
|
||||||
|
|
||||||
in_single_quote = false;
|
|
||||||
in_double_quote = false;
|
|
||||||
while (line[*i] != '\0')
|
|
||||||
{
|
|
||||||
if (line[*i] == '\'' && !in_double_quote)
|
|
||||||
in_single_quote = !in_single_quote;
|
|
||||||
else if (line[*i] == '"' && !in_single_quote)
|
|
||||||
in_double_quote = !in_double_quote;
|
|
||||||
else if (!in_single_quote && !in_double_quote
|
|
||||||
&& (isspace(line[*i]) || is_meta(line[*i])))
|
|
||||||
break;
|
|
||||||
(*i)++;
|
|
||||||
}
|
|
||||||
return (token_new(TOKEN_WORD, ft_substr(line, start, *i - start)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool is_meta(
|
|
||||||
char c
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return (c == '|' || c == '<' || c == '>');
|
|
||||||
}
|
|
||||||
|
|||||||
64
src/parser/lexer_reader.c
Normal file
64
src/parser/lexer_reader.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* lexer_reader.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:13:23 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:13:23 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
static inline bool is_meta(char c);
|
||||||
|
|
||||||
|
t_token *read_token(
|
||||||
|
t_token_type type,
|
||||||
|
const char *line,
|
||||||
|
size_t *i
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const size_t start = *i;
|
||||||
|
size_t end;
|
||||||
|
|
||||||
|
while (is_meta(line[*i]))
|
||||||
|
(*i)++;
|
||||||
|
end = *i;
|
||||||
|
while (ft_isspace(line[*i]))
|
||||||
|
(*i)++;
|
||||||
|
return (token_new(type, ft_substr(line, start, end - start)));
|
||||||
|
}
|
||||||
|
|
||||||
|
t_token *read_word(
|
||||||
|
const char *line,
|
||||||
|
size_t *i
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const size_t start = *i;
|
||||||
|
bool in_single_quote;
|
||||||
|
bool in_double_quote;
|
||||||
|
|
||||||
|
in_single_quote = false;
|
||||||
|
in_double_quote = false;
|
||||||
|
while (line[*i] != '\0')
|
||||||
|
{
|
||||||
|
if (line[*i] == '\'' && !in_double_quote)
|
||||||
|
in_single_quote = !in_single_quote;
|
||||||
|
else if (line[*i] == '"' && !in_single_quote)
|
||||||
|
in_double_quote = !in_double_quote;
|
||||||
|
else if (!in_single_quote && !in_double_quote
|
||||||
|
&& (isspace(line[*i]) || is_meta(line[*i])))
|
||||||
|
break ;
|
||||||
|
(*i)++;
|
||||||
|
}
|
||||||
|
return (token_new(TOKEN_WORD, ft_substr(line, start, *i - start)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_meta(
|
||||||
|
char c
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return (c == '|' || c == '<' || c == '>');
|
||||||
|
}
|
||||||
67
src/parser/lexer_token.c
Normal file
67
src/parser/lexer_token.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* lexer_token.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:12:49 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:12:49 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
t_token_type get_token_type(
|
||||||
|
const char *str
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (str == NULL || str[0] == '\0')
|
||||||
|
return (TOKEN_WORD);
|
||||||
|
if (str[0] == '|')
|
||||||
|
return (TOKEN_PIPE);
|
||||||
|
if (str[0] == '<')
|
||||||
|
{
|
||||||
|
if (str[1] == '<')
|
||||||
|
return (TOKEN_HEREDOC);
|
||||||
|
return (TOKEN_REDIRECT_IN);
|
||||||
|
}
|
||||||
|
if (str[0] == '>')
|
||||||
|
{
|
||||||
|
if (str[1] == '>')
|
||||||
|
return (TOKEN_APPEND);
|
||||||
|
return (TOKEN_REDIRECT_OUT);
|
||||||
|
}
|
||||||
|
return (TOKEN_WORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_token *token_new(
|
||||||
|
t_token_type type,
|
||||||
|
char *text
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_token *token;
|
||||||
|
|
||||||
|
token = (t_token *)malloc(sizeof(t_token));
|
||||||
|
if (token == NULL)
|
||||||
|
return (NULL);
|
||||||
|
token->type = type;
|
||||||
|
token->value = text;
|
||||||
|
if (token->type == TOKEN_WORD && token->value == NULL)
|
||||||
|
{
|
||||||
|
free(token);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
return (token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void token_clear(
|
||||||
|
t_token *token
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (token != NULL)
|
||||||
|
{
|
||||||
|
free(token->value);
|
||||||
|
free(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,33 +6,14 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/10/22 18:37:38 by sede-san #+# #+# */
|
/* Created: 2025/10/22 18:37:38 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/13 18:17:00 by sede-san ### ########.fr */
|
/* Updated: 2026/02/13 21:22:06 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
|
|
||||||
static t_list *parse_tokens(
|
static t_list *parse_tokens(t_list *tokens);
|
||||||
t_list *tokens
|
|
||||||
);
|
|
||||||
|
|
||||||
static t_list *ft_lstfind(
|
|
||||||
t_list *lst,
|
|
||||||
bool (*pre)(void *)
|
|
||||||
);
|
|
||||||
|
|
||||||
static void expand_variable(
|
|
||||||
char **argument,
|
|
||||||
int *i,
|
|
||||||
t_minishell *minishell
|
|
||||||
);
|
|
||||||
|
|
||||||
static void expand(
|
|
||||||
t_list **commands,
|
|
||||||
t_minishell *minishell
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts a command line string into a list of commands.
|
* @brief Converts a command line string into a list of commands.
|
||||||
@@ -42,13 +23,13 @@ static void expand(
|
|||||||
*
|
*
|
||||||
* @return A list of commands or `NULL` on error.
|
* @return A list of commands or `NULL` on error.
|
||||||
*/
|
*/
|
||||||
t_list *parse(
|
t_list *parse(
|
||||||
char *line,
|
char *line,
|
||||||
t_minishell *minishell
|
t_minishell *minishell
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
t_list *commands;
|
t_list *commands;
|
||||||
t_list *tokens;
|
t_list *tokens;
|
||||||
|
|
||||||
if (line == NULL)
|
if (line == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -63,11 +44,10 @@ t_list *parse(
|
|||||||
* @brief Converts a list of tokens into a list of commands.
|
* @brief Converts a list of tokens into a list of commands.
|
||||||
*
|
*
|
||||||
* @param tokens The list of tokens to parse.
|
* @param tokens The list of tokens to parse.
|
||||||
* @param minishell The minishell instance.
|
|
||||||
*
|
*
|
||||||
* @return A list of commands or `NULL` on error.
|
* @return A list of commands or `NULL` on error.
|
||||||
*/
|
*/
|
||||||
static t_list *parse_tokens(
|
static t_list *parse_tokens(
|
||||||
t_list *tokens
|
t_list *tokens
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -81,7 +61,8 @@ static t_list *parse_tokens(
|
|||||||
commands = NULL;
|
commands = NULL;
|
||||||
current_token = tokens;
|
current_token = tokens;
|
||||||
if (((t_token *)current_token->content)->type == TOKEN_PIPE)
|
if (((t_token *)current_token->content)->type == TOKEN_PIPE)
|
||||||
return (syntax_error_unexpected_token((t_token *)current_token->content), NULL);
|
return (syntax_error_unexpected_token(
|
||||||
|
(t_token *)current_token->content), NULL);
|
||||||
while (current_token != NULL)
|
while (current_token != NULL)
|
||||||
{
|
{
|
||||||
command = command_new(¤t_token);
|
command = command_new(¤t_token);
|
||||||
@@ -103,404 +84,11 @@ static t_list *parse_tokens(
|
|||||||
if (current_token->next == NULL)
|
if (current_token->next == NULL)
|
||||||
{
|
{
|
||||||
ft_lstclear(&commands, (void (*)(void *))command_clear);
|
ft_lstclear(&commands, (void (*)(void *))command_clear);
|
||||||
return (syntax_error_unexpected_token((t_token *)current_token->content), NULL);
|
return (syntax_error_unexpected_token(
|
||||||
|
(t_token *)current_token->content), NULL);
|
||||||
}
|
}
|
||||||
current_token = current_token->next;
|
current_token = current_token->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (commands);
|
return (commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *replace_value(
|
|
||||||
char *original,
|
|
||||||
char *value,
|
|
||||||
int start,
|
|
||||||
int end
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const char *before = ft_substr(original, 0, start);
|
|
||||||
const char *after = ft_substr(original, end, ft_strlen(original) - end);
|
|
||||||
const char *expanded = ft_strnjoin(3, before, value, after);
|
|
||||||
|
|
||||||
free((char *)before);
|
|
||||||
free((char *)after);
|
|
||||||
return ((char *)expanded);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void expand_variable(
|
|
||||||
char **argument,
|
|
||||||
int *i,
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
char *expanded;
|
|
||||||
char *variable_name;
|
|
||||||
char *variable_value;
|
|
||||||
const int start = *i + 1;
|
|
||||||
int end;
|
|
||||||
|
|
||||||
end = start;
|
|
||||||
while (ft_isalnum((*argument)[end]) || (*argument)[end] == '_')
|
|
||||||
end++;
|
|
||||||
variable_name = ft_substr(*argument, start, end - start);
|
|
||||||
if (variable_name == NULL)
|
|
||||||
return (minishell->exit = true, malloc_error());
|
|
||||||
variable_value = get_env(variable_name, minishell);
|
|
||||||
free(variable_name);
|
|
||||||
if (variable_value == NULL)
|
|
||||||
variable_value = "";
|
|
||||||
expanded = replace_value(*argument, variable_value, start - 1, end);
|
|
||||||
if (expanded == NULL)
|
|
||||||
return (minishell->exit = true, malloc_error());
|
|
||||||
*i += ft_strlen(variable_value);
|
|
||||||
free(*argument);
|
|
||||||
*argument = expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void expand_argument(
|
|
||||||
char **argument,
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
bool in_single_quote;
|
|
||||||
bool in_double_quote;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
in_single_quote = false;
|
|
||||||
in_double_quote = false;
|
|
||||||
i = 0;
|
|
||||||
while ((*argument)[i] != '\0')
|
|
||||||
{
|
|
||||||
if ((*argument)[i] == '$' && !in_single_quote)
|
|
||||||
{
|
|
||||||
expand_variable(argument, &i, minishell);
|
|
||||||
if (*argument == NULL)
|
|
||||||
return (minishell->exit = true, malloc_error());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((*argument)[i] == '\'' && !in_double_quote)
|
|
||||||
in_single_quote = !in_single_quote;
|
|
||||||
else if ((*argument)[i] == '"' && !in_single_quote)
|
|
||||||
in_double_quote = !in_double_quote;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void expand(
|
|
||||||
t_list **commands,
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_list *current_command;
|
|
||||||
t_command *command;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
current_command = *commands;
|
|
||||||
while (current_command != NULL)
|
|
||||||
{
|
|
||||||
command = (t_command *)current_command->content;
|
|
||||||
i = 0;
|
|
||||||
while (i < command->argc)
|
|
||||||
{
|
|
||||||
expand_argument(&command->argv[i], minishell);
|
|
||||||
if (command->argv[i] == NULL)
|
|
||||||
ft_lstclear(commands, (void (*)(void *))command_clear);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (command == NULL)
|
|
||||||
return (ft_lstclear(commands, (void (*)(void *))command_clear));
|
|
||||||
current_command = current_command->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a new command from a list of tokens.
|
|
||||||
*
|
|
||||||
* @param tokens The list of tokens to create the command from.
|
|
||||||
*
|
|
||||||
* @return A new command or NULL on error.
|
|
||||||
*
|
|
||||||
* @note The `tokens` pointer is moved to the next command's tokens.
|
|
||||||
*/
|
|
||||||
t_command *command_new(
|
|
||||||
t_list **tokens
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_command *command;
|
|
||||||
t_list *current_token;
|
|
||||||
t_list *delimiter_token;
|
|
||||||
|
|
||||||
command = (t_command *)ft_calloc(1, sizeof(t_command));
|
|
||||||
if (command == NULL)
|
|
||||||
return (NULL);
|
|
||||||
current_token = *tokens;
|
|
||||||
delimiter_token = ft_lstfind(current_token, (bool (*)(void *))is_pipe);
|
|
||||||
while (command != NULL && current_token != delimiter_token)
|
|
||||||
command_add_tokens(&command, ¤t_token);
|
|
||||||
*tokens = current_token;
|
|
||||||
return (command);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a new redirection from a list of tokens.
|
|
||||||
*
|
|
||||||
* @param tokens The list of tokens to create the redirection from.
|
|
||||||
*
|
|
||||||
* @return A new redirection or `NULL` on error.
|
|
||||||
*/
|
|
||||||
t_redirection *redirection_new(
|
|
||||||
t_list **tokens
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_redirection *redirection;
|
|
||||||
t_token *token;
|
|
||||||
|
|
||||||
redirection = (t_redirection *)malloc(sizeof(t_redirection));
|
|
||||||
if (redirection == NULL)
|
|
||||||
return (malloc_error(), NULL);
|
|
||||||
token = (t_token *)(*tokens)->content;
|
|
||||||
redirection->type = token->type;
|
|
||||||
*tokens = (*tokens)->next;
|
|
||||||
if (*tokens == NULL)
|
|
||||||
{
|
|
||||||
free(redirection);
|
|
||||||
return (syntax_error_unexpected_token(NULL), NULL);
|
|
||||||
}
|
|
||||||
token = (t_token *)(*tokens)->content;
|
|
||||||
if (token->type != TOKEN_WORD)
|
|
||||||
{
|
|
||||||
free(redirection);
|
|
||||||
while (*tokens != NULL)
|
|
||||||
*tokens = (*tokens)->next;
|
|
||||||
return (syntax_error_unexpected_token(token), NULL);
|
|
||||||
}
|
|
||||||
redirection->target = ft_strdup(token->value);
|
|
||||||
if (redirection->target == NULL)
|
|
||||||
{
|
|
||||||
free(redirection);
|
|
||||||
return (malloc_error(), NULL);
|
|
||||||
}
|
|
||||||
*tokens = (*tokens)->next;
|
|
||||||
return (redirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void redirection_clear(
|
|
||||||
t_redirection *redirection
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (redirection != NULL)
|
|
||||||
{
|
|
||||||
free(redirection->target);
|
|
||||||
free(redirection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds a token to a command, updating the command's arguments and
|
|
||||||
* redirections as necessary.
|
|
||||||
*
|
|
||||||
* @param command The command to add the token to.
|
|
||||||
* @param tokens The list of tokens to add to the command.
|
|
||||||
*
|
|
||||||
* @note The `command` pointer can be free'd if there is an error while adding
|
|
||||||
* the token.
|
|
||||||
*/
|
|
||||||
void command_add_tokens(
|
|
||||||
t_command **command,
|
|
||||||
t_list **tokens
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_token *token;
|
|
||||||
|
|
||||||
token = (t_token *)(*tokens)->content;
|
|
||||||
if (is_redirection(token))
|
|
||||||
redirection_add(tokens, token, command);
|
|
||||||
else
|
|
||||||
words_add(tokens, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Converts a list of arguments into an array.
|
|
||||||
*
|
|
||||||
* @param args The list of arguments to convert.
|
|
||||||
* @param argc The number of arguments in the list.
|
|
||||||
*
|
|
||||||
* @return An array of arguments or `NULL` on error.
|
|
||||||
*
|
|
||||||
* @note The `args` list is cleared after the conversion and set to NULL.
|
|
||||||
*/
|
|
||||||
char **args_to_array(
|
|
||||||
t_list **args,
|
|
||||||
size_t argc
|
|
||||||
)
|
|
||||||
{
|
|
||||||
char **argv;
|
|
||||||
t_list *arg;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
argv = (char **)malloc(sizeof(char *) * (argc + 1));
|
|
||||||
if (argv == NULL)
|
|
||||||
return (NULL);
|
|
||||||
i = 0;
|
|
||||||
arg = *args;
|
|
||||||
while (arg != NULL)
|
|
||||||
{
|
|
||||||
argv[i] = (char *)arg->content;
|
|
||||||
arg = arg->next;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
argv[i] = NULL;
|
|
||||||
ft_lstclear_nodes(args);
|
|
||||||
return (argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds all consecutive word tokens to a command's argv and updates its
|
|
||||||
* argc accordingly.
|
|
||||||
*
|
|
||||||
* @param command The command to add the word tokens to.
|
|
||||||
* @param tokens The list of tokens to add to the command.
|
|
||||||
*/
|
|
||||||
void words_add(
|
|
||||||
t_list **tokens,
|
|
||||||
t_command **command
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_list *args;
|
|
||||||
t_list *arg;
|
|
||||||
t_token *token;
|
|
||||||
|
|
||||||
args = NULL;
|
|
||||||
arg = *tokens;
|
|
||||||
token = (t_token *)arg->content;
|
|
||||||
while (arg != NULL && token->type == TOKEN_WORD)
|
|
||||||
{
|
|
||||||
ft_lstadd_back(&args, ft_lstnew(ft_strdup(token->value)));
|
|
||||||
(*command)->argc++;
|
|
||||||
arg = arg->next;
|
|
||||||
if (arg != NULL)
|
|
||||||
token = (t_token *)arg->content;
|
|
||||||
}
|
|
||||||
*tokens = arg;
|
|
||||||
(*command)->argv = args_to_array(&args, (*command)->argc);
|
|
||||||
ft_lstclear_nodes(&args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void redirection_add(
|
|
||||||
t_list **tokens,
|
|
||||||
t_token *token,
|
|
||||||
t_command **command
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_redirection *redirection;
|
|
||||||
t_list *redirection_tokens;
|
|
||||||
|
|
||||||
redirection = redirection_new(tokens);
|
|
||||||
if (redirection == NULL)
|
|
||||||
{
|
|
||||||
command_clear(*command);
|
|
||||||
*command = NULL;
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
redirection_tokens = ft_lstnew(redirection);
|
|
||||||
if (redirection_tokens == NULL)
|
|
||||||
{
|
|
||||||
free(redirection);
|
|
||||||
return (malloc_error());
|
|
||||||
}
|
|
||||||
if (token->type == TOKEN_HEREDOC)
|
|
||||||
ft_lstadd_back(&(*command)->heredocs, redirection_tokens);
|
|
||||||
else
|
|
||||||
ft_lstadd_back(&(*command)->redirections, redirection_tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if a token is a redirection token.
|
|
||||||
*
|
|
||||||
* @param token The token to check.
|
|
||||||
*
|
|
||||||
* @return `true` if the token is a redirection token, `false` otherwise.
|
|
||||||
*/
|
|
||||||
bool is_redirection(
|
|
||||||
t_token *token
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return (token->type == TOKEN_REDIRECT_IN
|
|
||||||
|| token->type == TOKEN_REDIRECT_OUT
|
|
||||||
|| token->type == TOKEN_APPEND
|
|
||||||
|| token->type == TOKEN_HEREDOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
void command_clear_argv(
|
|
||||||
t_command *command
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (command->argv != NULL)
|
|
||||||
{
|
|
||||||
i = 0;
|
|
||||||
while (i < command->argc)
|
|
||||||
{
|
|
||||||
free(command->argv[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
free(command->argv);
|
|
||||||
command->argv = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Clears a command, freeing all associated memory.
|
|
||||||
*
|
|
||||||
* @param command The command to clear.
|
|
||||||
*/
|
|
||||||
void command_clear(
|
|
||||||
t_command *command
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (command != NULL)
|
|
||||||
{
|
|
||||||
command_clear_argv(command);
|
|
||||||
ft_lstclear(&command->redirections, (void (*)(void *))redirection_clear);
|
|
||||||
ft_lstclear(&command->heredocs, (void (*)(void *))redirection_clear);
|
|
||||||
free(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if a token is a pipe token.
|
|
||||||
*
|
|
||||||
* @param token The token to check.
|
|
||||||
*
|
|
||||||
* @return `true` if the token is a pipe token, `false` otherwise.
|
|
||||||
*/
|
|
||||||
bool is_pipe(
|
|
||||||
t_token *token)
|
|
||||||
{
|
|
||||||
return (token->type == TOKEN_PIPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Finds a node in a linked list that satisfies a given predicate.
|
|
||||||
*
|
|
||||||
* @param lst The linked list to search through.
|
|
||||||
* @param pre The predicate function to apply to each node's content.
|
|
||||||
*
|
|
||||||
* @returns The first node that satisfies the predicate or `NULL` if no such
|
|
||||||
* node exists or if the list is `NULL`.
|
|
||||||
*/
|
|
||||||
t_list *ft_lstfind(
|
|
||||||
t_list *lst,
|
|
||||||
bool (*pre)(void *))
|
|
||||||
{
|
|
||||||
while (lst != NULL)
|
|
||||||
{
|
|
||||||
if (pre(lst->content))
|
|
||||||
return (lst);
|
|
||||||
lst = lst->next;
|
|
||||||
}
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|||||||
120
src/parser/parser_command.c
Normal file
120
src/parser/parser_command.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* parser_command.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:26:42 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:26:42 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
static t_list *ft_lstfind(t_list *lst, bool (*pre)(void *));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new command from a list of tokens.
|
||||||
|
*
|
||||||
|
* @param tokens The list of tokens to create the command from.
|
||||||
|
*
|
||||||
|
* @return A new command or NULL on error.
|
||||||
|
*
|
||||||
|
* @note The `tokens` pointer is moved to the next command's tokens.
|
||||||
|
*/
|
||||||
|
t_command *command_new(
|
||||||
|
t_list **tokens
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_command *command;
|
||||||
|
t_list *current_token;
|
||||||
|
t_list *delimiter_token;
|
||||||
|
|
||||||
|
command = (t_command *)ft_calloc(1, sizeof(t_command));
|
||||||
|
if (command == NULL)
|
||||||
|
return (NULL);
|
||||||
|
current_token = *tokens;
|
||||||
|
delimiter_token = ft_lstfind(current_token, (bool (*)(void *))is_pipe);
|
||||||
|
while (command != NULL && current_token != delimiter_token)
|
||||||
|
command_add_tokens(&command, ¤t_token);
|
||||||
|
*tokens = current_token;
|
||||||
|
return (command);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a token to a command, updating the command's arguments and
|
||||||
|
* redirections as necessary.
|
||||||
|
*
|
||||||
|
* @param command The command to add the token to.
|
||||||
|
* @param tokens The list of tokens to add to the command.
|
||||||
|
*
|
||||||
|
* @note The `command` pointer can be free'd if there is an error while adding
|
||||||
|
* the token.
|
||||||
|
*/
|
||||||
|
void command_add_tokens(
|
||||||
|
t_command **command,
|
||||||
|
t_list **tokens
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_token *token;
|
||||||
|
|
||||||
|
token = (t_token *)(*tokens)->content;
|
||||||
|
if (is_redirection(token))
|
||||||
|
redirection_add(tokens, token, command);
|
||||||
|
else
|
||||||
|
words_add(tokens, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a token is a redirection token.
|
||||||
|
*
|
||||||
|
* @param token The token to check.
|
||||||
|
*
|
||||||
|
* @return `true` if the token is a redirection token, `false` otherwise.
|
||||||
|
*/
|
||||||
|
bool is_redirection(
|
||||||
|
t_token *token
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return (token->type == TOKEN_REDIRECT_IN
|
||||||
|
|| token->type == TOKEN_REDIRECT_OUT
|
||||||
|
|| token->type == TOKEN_APPEND
|
||||||
|
|| token->type == TOKEN_HEREDOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a token is a pipe token.
|
||||||
|
*
|
||||||
|
* @param token The token to check.
|
||||||
|
*
|
||||||
|
* @return `true` if the token is a pipe token, `false` otherwise.
|
||||||
|
*/
|
||||||
|
bool is_pipe(
|
||||||
|
t_token *token
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return (token->type == TOKEN_PIPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finds a node in a linked list that satisfies a given predicate.
|
||||||
|
*
|
||||||
|
* @param lst The linked list to search through.
|
||||||
|
* @param pre The predicate function to apply to each node's content.
|
||||||
|
*
|
||||||
|
* @returns The first node that satisfies the predicate or `NULL` if no such
|
||||||
|
* node exists or if the list is `NULL`.
|
||||||
|
*/
|
||||||
|
static t_list *ft_lstfind(
|
||||||
|
t_list *lst,
|
||||||
|
bool (*pre)(void *))
|
||||||
|
{
|
||||||
|
while (lst != NULL)
|
||||||
|
{
|
||||||
|
if (pre(lst->content))
|
||||||
|
return (lst);
|
||||||
|
lst = lst->next;
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
124
src/parser/parser_expand.c
Normal file
124
src/parser/parser_expand.c
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* parser_expand.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:24:45 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/14 01:51:57 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include "variables.h"
|
||||||
|
|
||||||
|
static char *replace_value(char *original, char *value, int start, int end);
|
||||||
|
static void expand_variable(char **argument, int *i, t_minishell *minishell);
|
||||||
|
static void expand_argument(char **argument, t_minishell *minishell);
|
||||||
|
|
||||||
|
static char *replace_value(
|
||||||
|
char *original,
|
||||||
|
char *value,
|
||||||
|
int start,
|
||||||
|
int end
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const char *before = ft_substr(original, 0, start);
|
||||||
|
const char *after = ft_substr(original, end, ft_strlen(original) - end);
|
||||||
|
const char *expanded = ft_strnjoin(3, before, value, after);
|
||||||
|
|
||||||
|
free((char *)before);
|
||||||
|
free((char *)after);
|
||||||
|
return ((char *)expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expand_variable(
|
||||||
|
char **argument,
|
||||||
|
int *i,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char *expanded;
|
||||||
|
char *variable_name;
|
||||||
|
char *variable_value;
|
||||||
|
const int start = *i + 1;
|
||||||
|
int end;
|
||||||
|
|
||||||
|
end = start;
|
||||||
|
while (ft_isalnum((*argument)[end]) || (*argument)[end] == '_'
|
||||||
|
|| (*argument)[end] == '?')
|
||||||
|
end++;
|
||||||
|
variable_name = ft_substr(*argument, start, end - start);
|
||||||
|
if (variable_name == NULL)
|
||||||
|
return (minishell->exit = true, malloc_error());
|
||||||
|
variable_value = get_var(variable_name, minishell);
|
||||||
|
free(variable_name);
|
||||||
|
if (variable_value == NULL)
|
||||||
|
variable_value = "";
|
||||||
|
expanded = replace_value(*argument, variable_value, start - 1, end);
|
||||||
|
if (expanded == NULL)
|
||||||
|
return (minishell->exit = true, malloc_error());
|
||||||
|
*i += ft_strlen(variable_value);
|
||||||
|
free(*argument);
|
||||||
|
*argument = expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expand_argument(
|
||||||
|
char **argument,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
bool in_single_quote;
|
||||||
|
bool in_double_quote;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
in_single_quote = false;
|
||||||
|
in_double_quote = false;
|
||||||
|
i = 0;
|
||||||
|
while ((*argument)[i] != '\0')
|
||||||
|
{
|
||||||
|
if ((*argument)[i] == '$' && !in_single_quote)
|
||||||
|
{
|
||||||
|
expand_variable(argument, &i, minishell);
|
||||||
|
if (*argument == NULL)
|
||||||
|
return (minishell->exit = true, malloc_error());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((*argument)[i] == '\'' && !in_double_quote)
|
||||||
|
in_single_quote = !in_single_quote;
|
||||||
|
else if ((*argument)[i] == '"' && !in_single_quote)
|
||||||
|
in_double_quote = !in_double_quote;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void expand(
|
||||||
|
t_list **commands,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_list *current_command;
|
||||||
|
t_command *command;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
current_command = *commands;
|
||||||
|
while (current_command != NULL)
|
||||||
|
{
|
||||||
|
command = (t_command *)current_command->content;
|
||||||
|
i = 0;
|
||||||
|
while (i < command->argc)
|
||||||
|
{
|
||||||
|
expand_argument(&command->argv[i], minishell);
|
||||||
|
if (command->argv[i] == NULL)
|
||||||
|
ft_lstclear(commands, (void (*)(void *))command_clear);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (command == NULL)
|
||||||
|
return (ft_lstclear(commands, (void (*)(void *))command_clear));
|
||||||
|
current_command = current_command->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/parser/parser_redirection.c
Normal file
98
src/parser/parser_redirection.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* parser_redirection.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:28:35 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:28:35 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
|
static t_redirection *redirection_new(t_list **tokens);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new redirection from a list of tokens.
|
||||||
|
*
|
||||||
|
* @param tokens The list of tokens to create the redirection from.
|
||||||
|
*
|
||||||
|
* @return A new redirection or `NULL` on error.
|
||||||
|
*/
|
||||||
|
static t_redirection *redirection_new(
|
||||||
|
t_list **tokens
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_redirection *redirection;
|
||||||
|
t_token *token;
|
||||||
|
|
||||||
|
redirection = (t_redirection *)malloc(sizeof(t_redirection));
|
||||||
|
if (redirection == NULL)
|
||||||
|
return (malloc_error(), NULL);
|
||||||
|
token = (t_token *)(*tokens)->content;
|
||||||
|
redirection->type = token->type;
|
||||||
|
*tokens = (*tokens)->next;
|
||||||
|
if (*tokens == NULL)
|
||||||
|
{
|
||||||
|
free(redirection);
|
||||||
|
return (syntax_error_unexpected_token(NULL), NULL);
|
||||||
|
}
|
||||||
|
token = (t_token *)(*tokens)->content;
|
||||||
|
if (token->type != TOKEN_WORD)
|
||||||
|
{
|
||||||
|
free(redirection);
|
||||||
|
while (*tokens != NULL)
|
||||||
|
*tokens = (*tokens)->next;
|
||||||
|
return (syntax_error_unexpected_token(token), NULL);
|
||||||
|
}
|
||||||
|
redirection->target = ft_strdup(token->value);
|
||||||
|
if (redirection->target == NULL)
|
||||||
|
{
|
||||||
|
free(redirection);
|
||||||
|
return (malloc_error(), NULL);
|
||||||
|
}
|
||||||
|
*tokens = (*tokens)->next;
|
||||||
|
return (redirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void redirection_clear(
|
||||||
|
t_redirection *redirection
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (redirection != NULL)
|
||||||
|
{
|
||||||
|
free(redirection->target);
|
||||||
|
free(redirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void redirection_add(
|
||||||
|
t_list **tokens,
|
||||||
|
t_token *token,
|
||||||
|
t_command **command
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_redirection *redirection;
|
||||||
|
t_list *redirection_tokens;
|
||||||
|
|
||||||
|
redirection = redirection_new(tokens);
|
||||||
|
if (redirection == NULL)
|
||||||
|
{
|
||||||
|
command_clear(*command);
|
||||||
|
*command = NULL;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
redirection_tokens = ft_lstnew(redirection);
|
||||||
|
if (redirection_tokens == NULL)
|
||||||
|
{
|
||||||
|
free(redirection);
|
||||||
|
return (malloc_error());
|
||||||
|
}
|
||||||
|
if (token->type == TOKEN_HEREDOC)
|
||||||
|
ft_lstadd_back(&(*command)->heredocs, redirection_tokens);
|
||||||
|
else
|
||||||
|
ft_lstadd_back(&(*command)->redirections, redirection_tokens);
|
||||||
|
}
|
||||||
121
src/parser/parser_words.c
Normal file
121
src/parser/parser_words.c
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* parser_words.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:29:44 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:29:44 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
char **args_to_array(t_list **args, size_t argc);
|
||||||
|
void command_clear_argv(t_command *command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts a list of arguments into an array.
|
||||||
|
*
|
||||||
|
* @param args The list of arguments to convert.
|
||||||
|
* @param argc The number of arguments in the list.
|
||||||
|
*
|
||||||
|
* @return An array of arguments or `NULL` on error.
|
||||||
|
*
|
||||||
|
* @note The `args` list is cleared after the conversion and set to NULL.
|
||||||
|
*/
|
||||||
|
char **args_to_array(
|
||||||
|
t_list **args,
|
||||||
|
size_t argc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
t_list *arg;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
argv = (char **)malloc(sizeof(char *) * (argc + 1));
|
||||||
|
if (argv == NULL)
|
||||||
|
return (NULL);
|
||||||
|
i = 0;
|
||||||
|
arg = *args;
|
||||||
|
while (arg != NULL)
|
||||||
|
{
|
||||||
|
argv[i] = (char *)arg->content;
|
||||||
|
arg = arg->next;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
argv[i] = NULL;
|
||||||
|
ft_lstclear_nodes(args);
|
||||||
|
return (argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds all consecutive word tokens to a command's argv and updates its
|
||||||
|
* argc accordingly.
|
||||||
|
*
|
||||||
|
* @param command The command to add the word tokens to.
|
||||||
|
* @param tokens The list of tokens to add to the command.
|
||||||
|
*/
|
||||||
|
void words_add(
|
||||||
|
t_list **tokens,
|
||||||
|
t_command **command
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_list *args;
|
||||||
|
t_list *arg;
|
||||||
|
t_token *token;
|
||||||
|
|
||||||
|
args = NULL;
|
||||||
|
arg = *tokens;
|
||||||
|
token = (t_token *)arg->content;
|
||||||
|
while (arg != NULL && token->type == TOKEN_WORD)
|
||||||
|
{
|
||||||
|
ft_lstadd_back(&args, ft_lstnew(ft_strdup(token->value)));
|
||||||
|
(*command)->argc++;
|
||||||
|
arg = arg->next;
|
||||||
|
if (arg != NULL)
|
||||||
|
token = (t_token *)arg->content;
|
||||||
|
}
|
||||||
|
*tokens = arg;
|
||||||
|
(*command)->argv = args_to_array(&args, (*command)->argc);
|
||||||
|
ft_lstclear_nodes(&args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_clear_argv(
|
||||||
|
t_command *command
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (command->argv != NULL)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
while (i < command->argc)
|
||||||
|
{
|
||||||
|
free(command->argv[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
free(command->argv);
|
||||||
|
command->argv = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears a command, freeing all associated memory.
|
||||||
|
*
|
||||||
|
* @param command The command to clear.
|
||||||
|
*/
|
||||||
|
void command_clear(
|
||||||
|
t_command *command
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (command != NULL)
|
||||||
|
{
|
||||||
|
command_clear_argv(command);
|
||||||
|
ft_lstclear(&command->redirections,
|
||||||
|
(void (*)(void *))redirection_clear);
|
||||||
|
ft_lstclear(&command->heredocs, (void (*)(void *))redirection_clear);
|
||||||
|
free(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,65 +6,33 @@
|
|||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/12/01 09:12:39 by sede-san #+# #+# */
|
/* Created: 2025/12/01 09:12:39 by sede-san #+# #+# */
|
||||||
/* Updated: 2026/02/08 19:44:15 by sede-san ### ########.fr */
|
/* Updated: 2026/02/14 01:32:42 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
#include "minishell.h"
|
#include "minishell.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
#include "variables.h"
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parses and stores environment variables from envp array into a hashmap
|
* @brief Retrieves the value of an environment variable from the shell's
|
||||||
|
* environment hashmap.
|
||||||
*
|
*
|
||||||
* This function iterates through the environment variables array (envp) and
|
* This function searches for the specified environment variable name in the
|
||||||
* splits each variable string on the '=' delimiter to separate the variable
|
* minishell's environment variable hashmap and returns its associated value.
|
||||||
* name from its value. Each name-value pair is then stored in the minishell's
|
|
||||||
* environment hashmap for later retrieval.
|
|
||||||
*
|
*
|
||||||
* @param envp Array of environment variable strings in "NAME=value" format
|
* @param name The name of the environment variable to retrieve.
|
||||||
* @param msh Pointer to the minishell structure containing the environment
|
* @param minishell Pointer to the minishell object.
|
||||||
* hashmap
|
|
||||||
*
|
*
|
||||||
* @note The function assumes envp strings are in the standard format
|
* @return The value of the environment variable if found, NULL if not found
|
||||||
* "NAME=value"
|
|
||||||
*/
|
*/
|
||||||
void set_envp(
|
char *get_env(
|
||||||
char **envp,
|
const char *name,
|
||||||
t_minishell *msh
|
t_minishell *minishell
|
||||||
) {
|
)
|
||||||
char *equal_sign;
|
{
|
||||||
char *key;
|
return (ft_hashmap_get(minishell->variables.environment, name));
|
||||||
char *value;
|
|
||||||
|
|
||||||
if (msh == NULL || envp == NULL)
|
|
||||||
return ;
|
|
||||||
msh->variables.environment
|
|
||||||
= ft_hashmap_new(32, ft_hashmap_hashstr, ft_hashmap_strcmp);
|
|
||||||
if (msh->variables.environment == NULL)
|
|
||||||
return ;
|
|
||||||
while (*envp != NULL)
|
|
||||||
{
|
|
||||||
equal_sign = ft_strchr(*envp, '=');
|
|
||||||
if (equal_sign == NULL)
|
|
||||||
{
|
|
||||||
key = ft_strdup(*envp);
|
|
||||||
value = ft_strdup("");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
key = ft_substr(*envp, 0, equal_sign - *envp);
|
|
||||||
value = ft_strdup(equal_sign + 1);
|
|
||||||
}
|
|
||||||
if (key == NULL || value == NULL)
|
|
||||||
{
|
|
||||||
free(key);
|
|
||||||
free(value);
|
|
||||||
ft_hashmap_clear(&msh->variables.environment, free);
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
ft_hashmap_put(msh->variables.environment, key, value);
|
|
||||||
envp++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,29 +43,72 @@ void set_envp(
|
|||||||
* the old value is freed to prevent memory leaks. If the variable is new,
|
* the old value is freed to prevent memory leaks. If the variable is new,
|
||||||
* a duplicate of the key name is created for storage.
|
* a duplicate of the key name is created for storage.
|
||||||
*
|
*
|
||||||
* @param env_name The name of the environment variable to set
|
* @param name The name of the environment variable to set
|
||||||
* @param env_value The value to assign to the environment variable
|
* @param value The value to assign to the environment variable
|
||||||
* @param msh Pointer to the minishell structure containing the
|
* @param minishell Pointer to the minishell object.
|
||||||
* environment hashmap
|
|
||||||
*/
|
*/
|
||||||
void set_env(
|
void set_env(
|
||||||
const char *env_name,
|
const char *name,
|
||||||
char *env_value,
|
char *value,
|
||||||
t_minishell *msh
|
t_minishell *minishell
|
||||||
) {
|
)
|
||||||
t_hashmap *environment;
|
{
|
||||||
const char *key;
|
t_hashmap *environment;
|
||||||
char *old_value;
|
char *key;
|
||||||
|
char *val;
|
||||||
|
char *old_value;
|
||||||
|
|
||||||
environment = msh->variables.environment;
|
environment = minishell->variables.environment;
|
||||||
key = env_name;
|
key = (char *)name;
|
||||||
if (!ft_hashmap_contains_key(environment, key))
|
if (key != NULL && !ft_hashmap_contains_key(environment, key))
|
||||||
key = ft_strdup(env_name);
|
{
|
||||||
old_value = ft_hashmap_put(environment, key, ft_strdup(env_value));
|
key = ft_strdup(name);
|
||||||
|
if (key == NULL)
|
||||||
|
{
|
||||||
|
minishell->exit = true;
|
||||||
|
malloc_error();
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val = value;
|
||||||
|
if (val != NULL)
|
||||||
|
val = ft_strdup(value);
|
||||||
|
if (val == NULL)
|
||||||
|
{
|
||||||
|
if (key != name)
|
||||||
|
free(key);
|
||||||
|
minishell->exit = true;
|
||||||
|
malloc_error();
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
old_value = ft_hashmap_put(environment, key, val);
|
||||||
if (old_value != NULL)
|
if (old_value != NULL)
|
||||||
free(old_value);
|
free(old_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes an environment variable by name.
|
||||||
|
*
|
||||||
|
* @param name The name of the environment variable to remove.
|
||||||
|
* @param minishell Pointer to the minishell structure.
|
||||||
|
*
|
||||||
|
* @note If the environment variable exists, it will be removed from the hashmap
|
||||||
|
* and its associated value will be freed.
|
||||||
|
*/
|
||||||
|
void unset_env(
|
||||||
|
const char *name,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_hashmap *environment;
|
||||||
|
char *val;
|
||||||
|
|
||||||
|
environment = minishell->variables.environment;
|
||||||
|
val = ft_hashmap_remove(environment, (void *)name);
|
||||||
|
if (val != NULL)
|
||||||
|
free(val);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts the environment variables hashmap to an envp array format.
|
* @brief Converts the environment variables hashmap to an envp array format.
|
||||||
*
|
*
|
||||||
@@ -105,7 +116,7 @@ void set_env(
|
|||||||
* environment hashmap and converts them into a NULL-terminated array of
|
* environment hashmap and converts them into a NULL-terminated array of
|
||||||
* strings in the format "KEY=VALUE".
|
* strings in the format "KEY=VALUE".
|
||||||
*
|
*
|
||||||
* @param msh Pointer to the minishell structure containing the environment
|
* @param minishell Pointer to the minishell structure containing the environment
|
||||||
* variables hashmap.
|
* variables hashmap.
|
||||||
*
|
*
|
||||||
* @return A dynamically allocated array of strings representing environment
|
* @return A dynamically allocated array of strings representing environment
|
||||||
@@ -120,17 +131,18 @@ void set_env(
|
|||||||
* the NULL terminator.
|
* the NULL terminator.
|
||||||
*/
|
*/
|
||||||
char **get_envp(
|
char **get_envp(
|
||||||
t_minishell *msh
|
t_minishell *minishell
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
char **envp;
|
char **envp;
|
||||||
t_list *env_list;
|
t_list *env_list;
|
||||||
t_list *env;
|
t_list *env;
|
||||||
t_map_entry *entry;
|
t_map_entry *entry;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
env_list = ft_hashmap_entries(msh->variables.environment);
|
env_list = ft_hashmap_entries(minishell->variables.environment);
|
||||||
envp = (char **)malloc(
|
envp = (char **)malloc(
|
||||||
(msh->variables.environment->size + 1) * sizeof(char *)
|
(minishell->variables.environment->size + 1) * sizeof(char *)
|
||||||
);
|
);
|
||||||
if (envp != NULL)
|
if (envp != NULL)
|
||||||
{
|
{
|
||||||
@@ -149,44 +161,39 @@ char **get_envp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Frees a dynamically allocated environment variables array
|
* @brief Parses and stores environment variables from envp array into a hashmap
|
||||||
*
|
*
|
||||||
* This function deallocates memory for an array of strings that was previously
|
* This function iterates through the environment variables array (envp) and
|
||||||
* allocated by `get_envp()`. It iterates through each string in the array,
|
* splits each variable string on the '=' delimiter to separate the variable
|
||||||
* frees the memory for individual strings, and then frees the array itself.
|
* name from its value. Each name-value pair is then stored in the minishell's
|
||||||
|
* environment hashmap for later retrieval.
|
||||||
*
|
*
|
||||||
* @param envp Pointer to the array of environment variable strings to be freed.
|
* @param envp Array of environment variable strings in "NAME=value" format
|
||||||
* Each string in the array should be dynamically allocated.
|
* @param minishell Pointer to the minishell structure containing the environment
|
||||||
* The array must be NULL-terminated.
|
* hashmap
|
||||||
|
*
|
||||||
|
* @note The function assumes envp strings are in the standard format
|
||||||
|
* "NAME=value"
|
||||||
*/
|
*/
|
||||||
void free_envp(
|
void set_envp(
|
||||||
char **envp
|
char **envp,
|
||||||
) {
|
t_minishell *minishell
|
||||||
size_t i;
|
)
|
||||||
|
{
|
||||||
|
t_hashmap **environment;
|
||||||
|
char **key_value;
|
||||||
|
|
||||||
i = -1;
|
if (minishell == NULL || envp == NULL)
|
||||||
while (envp[++i] != NULL)
|
return ;
|
||||||
free(envp[i]);
|
environment = &minishell->variables.environment;
|
||||||
free(envp);
|
*environment = ft_hashmap_new(32, ft_hashmap_hashstr, ft_hashmap_strcmp);
|
||||||
}
|
if (*environment == NULL)
|
||||||
|
return ;
|
||||||
/**
|
while (*envp != NULL)
|
||||||
* @brief Retrieves the value of an environment variable from the shell's
|
{
|
||||||
* environment hashmap.
|
key_value = ft_split(*envp, '=');
|
||||||
*
|
set_env(key_value[0], key_value[1], minishell);
|
||||||
* This function searches for the specified environment variable name in the
|
ft_free_split(key_value);
|
||||||
* minishell's environment variable hashmap and returns its associated value.
|
envp++;
|
||||||
*
|
}
|
||||||
* @param env_name The name of the environment variable to retrieve (e.g.,
|
|
||||||
* "PATH", "HOME")
|
|
||||||
* @param msh Pointer to the minishell structure containing the environment
|
|
||||||
* variables hashmap
|
|
||||||
*
|
|
||||||
* @return The value of the environment variable if found, NULL if not found
|
|
||||||
*/
|
|
||||||
char *get_env(
|
|
||||||
const char *env_name,
|
|
||||||
t_minishell *msh
|
|
||||||
) {
|
|
||||||
return (ft_hashmap_get(msh->variables.environment, env_name));
|
|
||||||
}
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/* ************************************************************************** */
|
|
||||||
/* */
|
|
||||||
/* ::: :::::::: */
|
|
||||||
/* environment_unset.c :+: :+: :+: */
|
|
||||||
/* +:+ +:+ +:+ */
|
|
||||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
|
||||||
/* +#+#+#+#+#+ +#+ */
|
|
||||||
/* Created: 2026/02/09 22:16:00 by codex #+# #+# */
|
|
||||||
/* Updated: 2026/02/09 22:16:00 by codex ### ########.fr */
|
|
||||||
/* */
|
|
||||||
/* ************************************************************************** */
|
|
||||||
|
|
||||||
#include "minishell.h"
|
|
||||||
#include "core.h"
|
|
||||||
|
|
||||||
void unset_env(
|
|
||||||
const char *env_name,
|
|
||||||
t_minishell *msh
|
|
||||||
){
|
|
||||||
t_hashmap *new_env;
|
|
||||||
t_list *entries;
|
|
||||||
t_list *current;
|
|
||||||
t_map_entry *entry;
|
|
||||||
|
|
||||||
new_env = ft_hashmap_new(32, ft_hashmap_hashstr, ft_hashmap_strcmp);
|
|
||||||
if (new_env == NULL)
|
|
||||||
return ;
|
|
||||||
entries = ft_hashmap_entries(msh->variables.environment);
|
|
||||||
current = entries;
|
|
||||||
while (current != NULL)
|
|
||||||
{
|
|
||||||
entry = current->content;
|
|
||||||
if (ft_strcmp(entry->key, env_name) != 0)
|
|
||||||
ft_hashmap_put(new_env,
|
|
||||||
ft_strdup(entry->key), ft_strdup(entry->value));
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
ft_lstclear_nodes(&entries);
|
|
||||||
ft_hashmap_clear(&msh->variables.environment, free);
|
|
||||||
msh->variables.environment = new_env;
|
|
||||||
}
|
|
||||||
120
src/variables/internal/internal.c
Normal file
120
src/variables/internal/internal.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* internal.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:29:43 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/14 01:39:36 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "minishell.h"
|
||||||
|
#include "core.h"
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the value of an internal variable by name.
|
||||||
|
*
|
||||||
|
* @param name The name of the internal variable to retrieve.
|
||||||
|
* @param minishell Pointer to the minishell structure.
|
||||||
|
*
|
||||||
|
* @return The value of the internal variable if found, or NULL if not found.
|
||||||
|
*/
|
||||||
|
char *get_int(
|
||||||
|
const char *name,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return (ft_hashmap_get(minishell->variables.internal, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stores a variable as internal.
|
||||||
|
*
|
||||||
|
* @param name The name of the internal variable to set.
|
||||||
|
* @param value The value to associate with the internal variable.
|
||||||
|
* @param minishell Pointer to the minishell structure.
|
||||||
|
*
|
||||||
|
* @note If the internal variable already exists, its value will be updated and
|
||||||
|
* the old value will be freed. If it does not exist, a new internal
|
||||||
|
* variable will be created.
|
||||||
|
*/
|
||||||
|
void set_int(
|
||||||
|
const char *name,
|
||||||
|
char *value,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_hashmap *internal;
|
||||||
|
char *key;
|
||||||
|
char *val;
|
||||||
|
char *old_val;
|
||||||
|
|
||||||
|
internal = minishell->variables.internal;
|
||||||
|
key = (char *)name;
|
||||||
|
if (key != NULL && !ft_hashmap_contains_key(internal, key))
|
||||||
|
{
|
||||||
|
key = ft_strdup(name);
|
||||||
|
if (key == NULL)
|
||||||
|
return (minishell->exit = true, malloc_error());
|
||||||
|
}
|
||||||
|
val = value;
|
||||||
|
if (val != NULL)
|
||||||
|
val = ft_strdup(value);
|
||||||
|
if (val == NULL)
|
||||||
|
{
|
||||||
|
if (key != name)
|
||||||
|
free(key);
|
||||||
|
return (minishell->exit = true, malloc_error());
|
||||||
|
}
|
||||||
|
old_val = ft_hashmap_put(internal, key, val);
|
||||||
|
if (old_val != NULL)
|
||||||
|
free(old_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes an internal variable by name.
|
||||||
|
*
|
||||||
|
* @param name The name of the internal variable to remove.
|
||||||
|
* @param minishell Pointer to the minishell structure.
|
||||||
|
*
|
||||||
|
* @note If the internal variable exists, it will be removed from the hashmap
|
||||||
|
* and its associated value will be freed.
|
||||||
|
*/
|
||||||
|
void unset_int(
|
||||||
|
const char *name,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
value = ft_hashmap_remove(minishell->variables.internal, (void *)name);
|
||||||
|
if (value != NULL)
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the internal variables hashmap with default values.
|
||||||
|
*
|
||||||
|
* @param minishell Pointer to the minishell structure to initialize.
|
||||||
|
*
|
||||||
|
* @warning This function must be called only once during the initialization of
|
||||||
|
* the minishell.
|
||||||
|
*/
|
||||||
|
void set_intp(
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (minishell == NULL)
|
||||||
|
return ;
|
||||||
|
minishell->variables.internal
|
||||||
|
= ft_hashmap_new(16, ft_hashmap_hashstr, ft_hashmap_strcmp);
|
||||||
|
if (minishell->variables.internal == NULL)
|
||||||
|
return ;
|
||||||
|
set_int("?", "0", minishell);
|
||||||
|
set_int("_", "minishell", minishell);
|
||||||
|
set_int("PS1", DEFAULT_PS1, minishell);
|
||||||
|
set_int("PS2", DEFAULT_PS2, minishell);
|
||||||
|
}
|
||||||
50
src/variables/variables.c
Normal file
50
src/variables/variables.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* variables.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:41:44 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/14 00:52:12 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "variables.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the value of a variable by name.
|
||||||
|
*
|
||||||
|
* @param name The name of the variable to retrieve.
|
||||||
|
* @param minishell Pointer to the minishell structure.
|
||||||
|
*
|
||||||
|
* @return The value of the variable if found, or NULL if not found.
|
||||||
|
*/
|
||||||
|
char *get_var(
|
||||||
|
const char *name,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
value = get_int(name, minishell);
|
||||||
|
if (value == NULL)
|
||||||
|
value = get_env(name, minishell);
|
||||||
|
return (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_var(const char *name, char *value, t_minishell *minishell)
|
||||||
|
{
|
||||||
|
if (ft_hashmap_contains_key(minishell->variables.internal, name))
|
||||||
|
set_int(name, value, minishell);
|
||||||
|
set_env(name, value, minishell);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unset_var(
|
||||||
|
const char *name,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unset_int(name, minishell);
|
||||||
|
unset_env(name, minishell);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user