Del bonus

This commit is contained in:
savalet
2025-04-03 19:41:46 +02:00
parent 80a03144b5
commit afdfd3b634
22 changed files with 0 additions and 1649 deletions

View File

@@ -1,170 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ast.h"
static
ast_t *parse_arg(ast_ctx_t *ctx, ast_t *node)
{
ctx->act_tok = get_next_token(ctx);
if (ctx->act_tok.type == T_SEMICOLON)
return node;
if (ctx->act_tok.type & (T_ARG | T_REDIRECT | T_APPEND |
T_IN_REDIRECT | T_HEREDOC)) {
if (!ensure_node_cap(node))
return NULL;
node->vector.tokens[node->vector.sz] = ctx->act_tok;
node->vector.sz++;
return parse_arg(ctx, node);
}
return node;
}
static
ast_t *fill_cmd_node(ast_ctx_t *ctx)
{
ast_t *node = create_node(ctx);
if (node == NULL)
return NULL;
node->type = N_CMD;
node->vector.cap = 2;
node->vector.tokens =
malloc(sizeof *node->vector.tokens * node->vector.cap);
if (node->vector.tokens == NULL)
return NULL;
node->tok = ctx->act_tok;
node->vector.sz = 0;
return parse_arg(ctx, node);
}
static
ast_t *parse_cmd(ast_ctx_t *ctx)
{
if (ctx->act_tok.type == T_EOF)
return ctx->ast;
if (ctx->act_tok.type != T_ARG)
if (!parser_eat(ctx, T_ARG))
return NULL;
return fill_cmd_node(ctx);
}
static
bool parse_pipe_childs(ast_ctx_t *ctx, ast_t *node)
{
if (!ensure_list_cap(node))
return false;
node->list.nodes[node->list.sz] = parse_cmd(ctx);
if (node->list.nodes[node->list.sz] == NULL)
return false;
node->list.sz++;
return true;
}
static
ast_t *parse_pipe(ast_ctx_t *ctx, ast_t *l_node)
{
ast_t *node = create_node(ctx);
if (node == NULL)
return NULL;
node->type = N_LST;
node->tok = ctx->act_tok;
node->list.cap = 2;
node->list.nodes = (ast_t **)malloc(sizeof(ast_t *) * node->list.cap);
if ((void *)node->list.nodes == NULL)
return NULL;
node->list.sz = 1;
node->list.nodes[0] = l_node;
if (!parser_eat(ctx, T_ARG))
return NULL;
while (ctx->act_tok.type & (T_ARG | T_PIPE))
if (!parse_pipe_childs(ctx, node))
return NULL;
return node;
}
static
ast_t *parse_semi(ast_ctx_t *ctx)
{
ast_t *l_node = parse_cmd(ctx);
if (ctx->act_tok.type == T_PIPE)
ctx->ast = parse_pipe(ctx, l_node);
else
return l_node;
return ctx->ast;
}
static
ast_t *create_semi_node(ast_ctx_t *ctx, ast_t *l_node)
{
ast_t *node = create_node(ctx);
if (node == NULL)
return NULL;
node->type = N_LST;
node->list.cap = 2;
node->list.nodes = (ast_t **)malloc(sizeof(ast_t *) * node->list.cap);
if ((void *)node->list.nodes == NULL)
return NULL;
node->list.sz = 1;
node->list.nodes[0] = l_node;
return node;
}
static
ast_t *fill_semi_node(ast_ctx_t *ctx, ast_t *node)
{
while (ctx->act_tok.type == T_SEMICOLON) {
ctx->act_tok = get_next_token(ctx);
if (ctx->act_tok.type == T_SEMICOLON)
continue;
if (!ensure_list_cap(node))
return false;
node->list.nodes[node->list.sz] = parse_semi(ctx);
if (node->list.nodes[node->list.sz] == NULL)
return false;
node->list.sz++;
}
return node;
}
static
void skip_semi(ast_ctx_t *ctx)
{
while (ctx->act_tok.type == T_SEMICOLON)
ctx->act_tok = get_next_token(ctx);
}
ast_t *parse_expression(ast_ctx_t *ctx)
{
ast_t *l_node;
ast_t *node;
if (ctx->act_tok.type == T_EOF)
return ctx->ast;
skip_semi(ctx);
l_node = parse_semi(ctx);
if (l_node == NULL)
return ctx->ast;
if (ctx->act_tok.type == T_SEMICOLON) {
node = create_semi_node(ctx, l_node);
if (node == NULL)
return NULL;
ctx->ast = fill_semi_node(ctx, node);
}
ctx->act_tok = get_next_token(ctx);
return parse_expression(ctx);
}

View File

@@ -1,102 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef AST_H
#define AST_H
#include <stddef.h>
#include <stdint.h>
#include "shell.h"
#include "env.h"
#define DEFAULT_AST_CAP 128
#define T_ALL 0xff
typedef enum {
T_SEMICOLON = 1 << 0, // ;
T_AND = 1 << 1, // &&
T_OR = 1 << 2, // ||
T_PIPE = 1 << 3, // |
T_BACKTICK = 1 << 4, // `
T_LEFT_PARENT = 1 << 5, // (
T_RIGHT_PARENT = 1 << 6, // )
T_PREV_CMD = 1 << 7, // !!
T_VAR = 1 << 8, // $
T_REDIRECT = 1 << 9, // >
T_APPEND = 1 << 10, // >>
T_HEREDOC = 1 << 11, // <
T_IN_REDIRECT = 1 << 12, // <
T_EOF = 1 << 13, // \0
T_ARG = 1 << 14,
T_INVALID = 1 << 15
} token_type_t;
typedef enum {
N_LST,
N_CMD,
N_BIN
} node_type_t;
typedef struct {
token_type_t type;
char *str;
size_t sz;
} token_t;
typedef struct {
token_type_t type;
char const *str;
uint8_t sz;
char const *name;
} tokens_list_t;
typedef struct ast_s ast_t;
typedef struct ast_s {
node_type_t type;
union {
struct {
ast_t *left;
ast_t *right;
} binary;
struct {
size_t sz;
size_t cap;
token_t *tokens;
} vector;
struct {
size_t sz;
size_t cap;
ast_t **nodes;
} list;
};
token_t tok;
} ast_t;
typedef struct {
size_t i;
size_t sz;
char *str;
size_t cap;
ast_t *ast;
token_t act_tok;
ast_t *first_node;
} ast_ctx_t;
extern const tokens_list_t TOKENS_LIST[];
ast_t *parse_expression(ast_ctx_t *ctx);
void print_ast(ast_ctx_t *ctx, ast_t *ast, size_t depth);
token_t get_next_token(ast_ctx_t *ctx);
int visitor(char *buffer, env_t *env, history_t *history);
ast_t *create_node(ast_ctx_t *ctx);
bool ensure_node_cap(ast_t *node);
bool ensure_list_cap(ast_t *node);
bool parser_eat(ast_ctx_t *ctx, token_type_t expected);
void free_ast(ast_ctx_t *ctx);
#endif /* AST_H */

View File

@@ -1,93 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdlib.h>
#include <unistd.h>
#include "ast.h"
#include "u_mem.h"
#include "u_str.h"
bool parser_eat(ast_ctx_t *ctx, token_type_t expected)
{
token_type_t prev_tok_type = ctx->act_tok.type;
ctx->act_tok = get_next_token(ctx);
if (!(ctx->act_tok.type & expected)) {
if (prev_tok_type == T_PIPE)
WRITE_CONST(STDERR_FILENO, "Invalid null command.\n");
else {
WRITE_CONST(STDERR_FILENO, "Parse error near \"");
write(STDERR_FILENO, ctx->act_tok.str, ctx->act_tok.sz);
WRITE_CONST(STDERR_FILENO, "\"\n");
}
return false;
}
return true;
}
ast_t *create_node(ast_ctx_t *ctx)
{
ast_t *new_ast;
if (ctx->ast == NULL)
return NULL;
if (ctx->sz + 1 == ctx->cap) {
new_ast = u_realloc(ctx->ast, sizeof *ctx->ast * ctx->sz,
sizeof *ctx->ast * (ctx->cap << 1));
if (new_ast == NULL)
return NULL;
ctx->ast = new_ast;
ctx->cap <<= 1;
}
ctx->ast[ctx->sz] = (ast_t){ 0 };
ctx->sz++;
return ctx->ast + ctx->sz - 1;
}
bool ensure_node_cap(ast_t *node)
{
token_t *temp;
if (node->vector.sz + 1 < node->vector.cap)
return true;
temp = u_realloc(node->vector.tokens,
sizeof *node->vector.tokens * node->vector.sz,
sizeof *node->vector.tokens * node->vector.cap << 1);
if (temp == NULL)
return false;
node->vector.cap <<= 1;
node->vector.tokens = temp;
return true;
}
bool ensure_list_cap(ast_t *node)
{
ast_t **temp;
if (node->list.sz + 1 < node->vector.cap)
return true;
temp = (ast_t **)u_realloc((void *)node->list.nodes,
sizeof *node->list.nodes * node->list.sz,
sizeof *node->list.nodes * node->vector.cap << 1);
if ((void *)temp == NULL)
return false;
node->list.cap <<= 1;
node->list.nodes = temp;
return true;
}
void free_ast(ast_ctx_t *ctx)
{
for (size_t i = 0; i < ctx->sz; i++) {
if (ctx->first_node[i].type == N_LST)
free((void *)ctx->first_node[i].list.nodes);
if (ctx->first_node[i].type == N_CMD)
free(ctx->first_node[i].vector.tokens);
}
free(ctx->first_node);
}

View File

@@ -1,149 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include "env.h"
#include "exec.h"
#include "u_mem.h"
#include "u_str.h"
int builtins_exit(ef_t *ef, char **args __attribute__((unused)))
{
if (ef->flags & F_PIPE &&
!(ef->out_fd == STDOUT_FILENO || ef->p_i == ef->p_sz - 1))
return RETURN_SUCCESS;
if (!(ef->flags & F_EXIT)) {
ef->flags |= F_EXIT;
return RETURN_SUCCESS;
}
free_env(ef->env);
free(ef->buffer);
WRITE_CONST(STDOUT_FILENO, "exit\n");
exit(ef->history->last_exit_code);
}
int builtins_env(ef_t *ef, char **args __attribute__((unused)))
{
for (size_t i = 0; i < ef->env->sz; i++) {
if (ef->env->env[i] == NULL)
continue;
write(ef->out_fd, ef->env->env[i], u_strlen(ef->env->env[i]));
WRITE_CONST(ef->out_fd, "\n");
}
return RETURN_SUCCESS;
}
int builtins_setenv(ef_t *ef, char **args)
{
if (args[1] == NULL)
return builtins_env(ef, args);
if (args[2] != NULL && args[3] != NULL) {
WRITE_CONST(STDERR_FILENO, "setenv: Too many arguments.\n");
return RETURN_FAILURE;
}
if (!isalpha(args[1][0]))
return (WRITE_CONST(STDERR_FILENO, "setenv: Variable name must begin"
" with a letter.\n"), RETURN_FAILURE);
if (!u_str_is_only_alnum(args[1]))
return (WRITE_CONST(STDERR_FILENO, "setenv: Variable name must contain"
" alphanumeric characters.\n"), RETURN_FAILURE);
if (!set_env(ef->env, args[1], args[2]))
return RETURN_FAILURE;
return RETURN_SUCCESS;
}
int builtins_unsetenv(ef_t *ef, char **args)
{
if (args[1] == NULL)
return (WRITE_CONST(STDERR_FILENO, "unsetenv: Too few arguments.\n"),
RETURN_FAILURE);
if (!unset_env(ef->env, args[1]))
return RETURN_FAILURE;
return RETURN_SUCCESS;
}
static
void cd_print_error(void)
{
switch (errno) {
case EACCES:
WRITE_CONST(STDERR_FILENO, ": Permission denied.\n");
break;
case ENOENT:
WRITE_CONST(STDERR_FILENO, ": No such file or directory.\n");
break;
case ENOTDIR:
WRITE_CONST(STDERR_FILENO, ": Not a directory.\n");
break;
default:
WRITE_CONST(STDERR_FILENO, ": Unknown error.\n");
}
}
static
char *get_current_dir(void)
{
size_t size = 64;
char *buffer = malloc(size);
char *new_buffer;
size_t max_it = 100;
if (!buffer)
return NULL;
while (getcwd(buffer, size) == NULL && max_it > 0) {
if (errno != ERANGE)
return (free(buffer), NULL);
size <<= 1;
new_buffer = u_realloc(buffer, u_strlen(buffer) + 1, size);
if (!new_buffer)
return (free(buffer), NULL);
buffer = new_buffer;
max_it--;
}
return buffer;
}
static
int builtins_cd_chdir(ef_t *ef, char **args, char *path)
{
char *act_pwd;
if (ef->history->last_chdir != NULL && args[1] != NULL
&& u_strcmp(args[1], "-") == 0)
path = ef->history->last_chdir;
act_pwd = get_current_dir();
if (chdir(path) < 0) {
write(STDERR_FILENO, path, u_strlen(path));
cd_print_error();
return RETURN_FAILURE;
}
free(ef->history->last_chdir);
ef->history->last_chdir = act_pwd;
return RETURN_SUCCESS;
}
int builtins_cd(ef_t *ef, char **args)
{
char *path = args[1];
if (!(ef->out_fd == STDOUT_FILENO || ef->p_i == ef->p_sz - 1))
return RETURN_SUCCESS;
if (path == NULL || u_strcmp(args[1], "~") == 0)
path = get_env_value(ef->env, "HOME");
if (path == NULL)
return RETURN_FAILURE;
if (args[1] != NULL && args[2] != NULL) {
WRITE_CONST(STDERR_FILENO, "cd: Too many arguments.\n");
return RETURN_FAILURE;
}
return builtins_cd_chdir(ef, args, path);
}

View File

@@ -1,28 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef BUILTINS_H
#define BUILTINS_H
#include "exec.h"
typedef struct {
char const *name;
int (*ptr)(ef_t *ef, char **args);
} builtins_t;
extern const builtins_t BUILTINS[];
extern const size_t BUILTINS_SZ;
int builtins_exit(ef_t *ef, char **args);
int builtins_env(ef_t *ef, char **args);
int builtins_setenv(ef_t *ef, char **args);
int builtins_unsetenv(ef_t *ef, char **args);
int builtins_cd(ef_t *ef, char **args);
int builtins_builtins(ef_t *ef, char **args);
int builtins_funny_double_dot(ef_t *ef, char **args);
#endif /* BUILTIND_H */

View File

@@ -1,26 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <unistd.h>
#include "builtins.h"
#include "common.h"
#include "u_str.h"
int builtins_builtins(ef_t *ef, char **args)
{
for (size_t i = 0; i < BUILTINS_SZ; i++) {
write(ef->out_fd, BUILTINS[i].name, u_strlen(BUILTINS[i].name));
WRITE_CONST(ef->out_fd, "\n");
}
return RETURN_SUCCESS;
}
int builtins_funny_double_dot(ef_t *ef, char **args)
{
return RETURN_SUCCESS;
}

View File

@@ -1,14 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef COMMON_H
#define COMMON_H
enum {
RETURN_SUCCESS = 0,
RETURN_FAILURE = 1
};
#endif /* COMMON_H */

View File

@@ -1,36 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef DEBUG_H
#define DEBUG_H
#include "vt100_esc_codes.h"
#include <stdio.h>
#define OMIT
#ifdef U_DEBUG_MODE
#define HEAD __FILE_NAME__, __LINE__
#define HEAD_FMT_FILE BOLD BLUE "%s" RESET
#define HEAD_FMT_LINE ":" BOLD PURPLE "%d" RESET
#define HEAD_FMT HEAD_FMT_FILE HEAD_FMT_LINE " "
#define ERR(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#define DEBUG_INTERNAL(fmt, ...) ERR(HEAD_FMT fmt, HEAD, __VA_ARGS__)
#define U_DEBUG(fmt, ...) DEBUG_INTERNAL(fmt, __VA_ARGS__)
#define U_DEBUG_MSG(msg) DEBUG_INTERNAL("%s\n", msg)
#define U_DEBUG_CALL(func, ...) func(__VA_ARGS__)
#else
#define U_DEBUG_CALL(func, ...) OMIT
#define U_DEBUG_MSG(msg) OMIT
#define U_DEBUG(fmt, ...) OMIT
#endif
#endif /* DEBUG_H */

View File

@@ -1,136 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "env.h"
#include "u_mem.h"
#include "u_str.h"
char *get_env_value(env_t *env, char const *key)
{
int key_len = u_strlen(key);
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
if (u_strcspn(env->env[i], '=') != key_len)
continue;
if (u_strcmp(env->env[i], key) == 0)
return env->env[i] + key_len + 1;
}
return NULL;
}
static
void unset_env_move(env_t *env, size_t i)
{
while (env->env[i]) {
env->env[i] = env->env[i + 1];
i++;
}
}
bool unset_env(env_t *env, char *key)
{
int key_len = u_strlen(key);
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
if (u_strcspn(env->env[i], '=') != key_len)
continue;
if (u_strcmp(env->env[i], key) == 0) {
unset_env_move(env, i);
env->sz--;
return true;
}
}
return false;
}
void free_env(env_t *env)
{
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
free(env->env[i]);
}
free((void *)env->env);
}
static __attribute__((nonnull))
bool ensure_env_capacity(env_t *env)
{
char **new_ptr;
if (env->sz < env->cap)
return true;
new_ptr = (char **)u_realloc((void *)env->env, sizeof *env->env * env->sz,
sizeof *env->env * env->cap << 1);
if (!new_ptr)
return false;
env->cap <<= 1;
env->env = new_ptr;
return true;
}
static
void env_bzero(char **env, size_t sz)
{
for (size_t i = 0; i < sz; i++)
env[i] = NULL;
}
bool set_env(env_t *env, char *key, char *value)
{
char *new_env = NULL;
size_t key_len = u_strlen(key);
size_t value_len = u_strlen(value);
if (get_env_value(env, key) != NULL)
unset_env(env, key);
env->sz++;
if (!ensure_env_capacity(env))
return false;
new_env = malloc(sizeof(char) * (key_len + value_len + 2));
if (new_env == NULL)
return false;
u_bzero(new_env, key_len + value_len + 2);
u_strcpy(new_env, key);
new_env[key_len] = '=';
if (value_len > 0)
u_strcpy(new_env + key_len + 1, value);
env->env[env->sz - 1] = new_env;
return true;
}
env_t parse_env(char **env)
{
env_t new_env = { 0, .cap = BASE_ENV_CAP };
new_env.env = (char **)malloc(sizeof(char *) * new_env.cap);
if (!new_env.env)
return (env_t){ 0, .env = NULL };
env_bzero(new_env.env, new_env.sz);
for (; *env != NULL; env++) {
if (!ensure_env_capacity(&new_env))
return (free((void *)new_env.env), (env_t){ 0 });
new_env.env[new_env.sz] = u_strdup(*env);
if (new_env.env[new_env.sz] == NULL)
return (free((void *)new_env.env), (env_t){ 0 });
new_env.sz++;
}
if (!ensure_env_capacity(&new_env))
return (free((void *)new_env.env), (env_t){ 0 });
new_env.env[new_env.sz] = NULL;
return new_env;
}

View File

@@ -1,30 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef ENV_H
#define ENV_H
#include <stdbool.h>
#include <stddef.h>
#define BASE_ENV_CAP 128
typedef struct {
size_t sz;
size_t cap;
char **env;
} env_t;
__attribute__((unused))
void free_env(env_t *env);
__attribute__((unused))
env_t parse_env(char **env);
__attribute__((unused))
char *get_env_value(env_t *env, char const *key);
__attribute__((unused))
bool unset_env(env_t *env, char *key);
__attribute__((nonnull(1, 2)))
bool set_env(env_t *env, char *key, char *value);
#endif

View File

@@ -1,209 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ast.h"
#include "builtins.h"
#include "common.h"
#include "debug.h"
#include "env.h"
#include "exec.h"
#include "path.h"
#include "u_mem.h"
#include "u_str.h"
const builtins_t BUILTINS[] = {
{ "builtins", &builtins_builtins },
{ "cd", &builtins_cd },
{ "chdir", &builtins_cd },
{ "env", &builtins_env },
{ "printenv", &builtins_env },
{ "setenv", &builtins_setenv },
{ "unsetenv", &builtins_unsetenv },
{ ":", &builtins_funny_double_dot },
{ "exit", &builtins_exit }
};
const size_t BUILTINS_SZ = sizeof BUILTINS / sizeof *BUILTINS;
static __attribute__((nonnull))
bool ensure_args_capacity(char ***args, size_t const sz, size_t *cap)
{
char **new_ptr;
if (sz < *cap)
return true;
new_ptr = (char **)u_realloc((void *)*args, sizeof *args * sz,
sizeof *args * *cap << 1);
if (!new_ptr)
return false;
*cap <<= 1;
*args = new_ptr;
return true;
}
static
char **parse_args(ef_t *ef, ast_t *node, env_t *env)
{
size_t sz = 1;
size_t cap = DEFAULT_ARGS_CAP;
char **args = (char **)malloc(sizeof *args * cap);
if (!args)
return NULL;
node->tok.str[node->tok.sz] = '\0';
args[0] = node->tok.str;
for (size_t i = 0; i < node->vector.sz; i++) {
if (ef->skip_sz > 0 && i >= ef->skip_i && i < ef->skip_i + ef->skip_sz)
continue;
ensure_args_capacity(&args, sz, &cap);
node->vector.tokens[i].str[node->vector.tokens[i].sz] = '\0';
if (*node->vector.tokens[i].str == '$'
&& get_env_value(env, node->vector.tokens[i].str + 1) != NULL) {
args[sz] = get_env_value(env, node->vector.tokens[i].str + 1);
} else if (*(node->vector.tokens[i].str + 1) == '?')
asprintf(&args[sz], "%d", ef->history->last_exit_code);
else
args[sz] = node->vector.tokens[i].str;
U_DEBUG("Args [%lu] [%s]\n", sz, args[sz]);
sz++;
}
ensure_args_capacity(&args, sz, &cap);
args[sz] = NULL;
return args;
}
static
int command_error(char *cmd, char **args, int error)
{
struct stat st;
if (access(cmd, F_OK) == -1) {
write(STDERR_FILENO, args[0], u_strlen(args[0]));
WRITE_CONST(STDERR_FILENO, ": Command not found.\n");
return 84;
}
stat(cmd, &st);
if (S_ISDIR(st.st_mode) || access(cmd, X_OK)) {
write(STDERR_FILENO, args[0], u_strlen(args[0]));
WRITE_CONST(STDERR_FILENO, ": Permission denied.\n");
return 84;
}
if (error == ENOEXEC) {
write(STDERR_FILENO, args[0], u_strlen(args[0]));
WRITE_CONST(STDERR_FILENO, ": Exec format error."
" Binary file not executable.\n");
return 0;
}
return 84;
}
static
void set_fd(ef_t *ef)
{
U_DEBUG("In fd [%d] out fd [%d]\n", ef->in_fd, ef->out_fd);
if (ef->in_fd != STDIN_FILENO) {
dup2(ef->in_fd, STDIN_FILENO);
close(ef->in_fd);
}
if (ef->out_fd != STDOUT_FILENO) {
dup2(ef->out_fd, STDOUT_FILENO);
close(ef->out_fd);
}
}
static
int launch_bin(char *full_bin_path, char **args, ef_t *ef)
{
int status;
pid_t pid = fork();
if (pid == 0) {
set_fd(ef);
if (execve(full_bin_path, args, ef->env->env) < 0) {
status = command_error(full_bin_path, args, errno);
free_env(ef->env);
free((void *)args);
exit((free(ef->buffer), status));
}
}
if (!(ef->flags & F_PIPE) || ef->p_i == ef->p_sz - 1)
waitpid(pid, &status, 0);
else
waitpid(pid, &status, WNOHANG);
if (WIFEXITED(status))
ef->history->last_exit_code =
ef->history->last_exit_code ?: WEXITSTATUS(status);
return status;
}
static
void status_handler(int status)
{
if (!WIFEXITED(status) && WIFSIGNALED(status) && WTERMSIG(status)) {
if (WTERMSIG(status) == SIGSEGV)
WRITE_CONST(STDERR_FILENO, "Segmentation fault");
if (WTERMSIG(status) == SIGTRAP)
WRITE_CONST(STDERR_FILENO, "Trace/BPT trap");
if (WTERMSIG(status) == SIGFPE)
WRITE_CONST(STDERR_FILENO, "Floating exception");
if (WCOREDUMP(status) && (WTERMSIG(status) == SIGSEGV ||
WTERMSIG(status) == SIGFPE || WTERMSIG(status) == SIGTRAP))
WRITE_CONST(STDERR_FILENO, " (core dumped)");
if (WTERMSIG(status) == SIGSEGV || WTERMSIG(status) == SIGFPE ||
WTERMSIG(status) == SIGTRAP)
WRITE_CONST(STDERR_FILENO, "\n");
}
}
static
bool builtins_launcher(ef_t *ef, char **args)
{
int bin_l = u_strlen(args[0]);
U_DEBUG("In fd [%d] out fd [%d]\n", ef->in_fd, ef->out_fd);
for (size_t i = 0; i < BUILTINS_SZ; i++) {
if (u_strlen(BUILTINS[i].name) != bin_l)
continue;
if (u_strcmp(BUILTINS[i].name, args[0]) == 0) {
ef->history->last_exit_code =
BUILTINS[i].ptr(ef, args);
return true;
}
}
return false;
}
int execute(ef_t *ef)
{
char *full_bin_path;
char **args;
int status;
args = parse_args(ef, ef->act_node, ef->env);
if (!args)
return RETURN_FAILURE;
if (builtins_launcher(ef, args))
return RETURN_SUCCESS;
full_bin_path = parse_full_bin_path(ef->env, args[0]);
if (full_bin_path == NULL)
return (free((void *)args), RETURN_FAILURE);
U_DEBUG("Found bin [%s]\n", full_bin_path);
status = launch_bin(full_bin_path, args, ef);
status_handler(status);
U_DEBUG("Exit code [%d]\n", ef->history->last_exit_code);
free(full_bin_path);
free((void *)args);
return ef->history->last_exit_code != 0 ? RETURN_FAILURE : RETURN_SUCCESS;
}

View File

@@ -1,50 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef EXEC_H
#define EXEC_H
#include "ast.h"
#include "env.h"
#include "shell.h"
#define DEFAULT_ARGS_CAP 1
typedef struct {
char **args;
size_t count;
size_t cap;
} args_t;
enum flags {
F_PIPE = 1 << 0,
F_RED = 1 << 1,
F_EXIT = 1 << 2
};
typedef struct {
char *buffer;
env_t *env;
history_t *history;
ast_ctx_t *ctx;
ast_t *act_node;
size_t skip_i;
size_t skip_sz;
uint8_t flags;
size_t p_i;
size_t p_sz;
int rin_fd;
int rout_fd;
int pipes[2];
int pin_fd;
int pout_fd;
int in_fd;
int out_fd;
} ef_t;
__attribute__((nonnull))
int execute(ef_t *ef);
#endif /* EXEC_H */

View File

@@ -1,16 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include "debug.h"
#include "shell.h"
int main(int ac __attribute__((unused)), char **av __attribute__((unused)),
char **env)
{
U_DEBUG_MSG("Debug mode activated.");
return shell(env);
}

View File

@@ -1,71 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "debug.h"
#include "env.h"
#include "path.h"
#include "u_str.h"
static
char *build_full_path(const char *token, const char *binary)
{
size_t len_token = u_strlen(token);
size_t len_bin = u_strlen(binary);
char *full_path = malloc(len_token + len_bin + 2);
if (!full_path)
return NULL;
u_strcpy(full_path, token);
full_path[len_token] = '/';
u_strcpy(full_path + len_token + 1, binary);
full_path[len_token + len_bin + 1] = '\0';
return full_path;
}
static
char *find_binary(const char *path_env, const char *binary, char **dup_path)
{
static char *saveptr = NULL;
char *token;
char *full_path;
if (path_env) {
*dup_path = u_strdup(path_env);
if (!*dup_path)
return NULL;
token = strtok_r(*dup_path, ":", &saveptr);
} else
token = strtok_r(NULL, ":", &saveptr);
if (!token)
return u_strdup(binary);
full_path = build_full_path(token, binary);
if (!full_path)
return NULL;
return access(full_path, X_OK) == 0 ? full_path : (free(full_path),
find_binary(NULL, binary, dup_path));
}
char *parse_full_bin_path(env_t *env, char *bin_name)
{
char const *path = get_env_value(env, "PATH");
char *dup_path = NULL;
char *full_bin_path;
if (path == NULL)
path = DEFAULT_PATH;
U_DEBUG("Used path [%s]\n", path);
full_bin_path = find_binary(path, bin_name, &dup_path);
U_DEBUG("Exec bin [%s]\n", full_bin_path);
if (full_bin_path == NULL)
return NULL;
free(dup_path);
return full_bin_path;
}

View File

@@ -1,15 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef PATH_H
#define PATH_H
#include "env.h"
#define DEFAULT_PATH "/usr/bin:."
char *parse_full_bin_path(env_t *env, char *bin_name);
#endif

View File

@@ -1,88 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "exec.h"
#include "u_str.h"
bool handle_out_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz)
{
if (!(node->vector.tokens[i].type & (T_REDIRECT | T_APPEND)))
return true;
if (i >= sz || node->vector.tokens[i + 1].type != T_ARG)
return (WRITE_CONST(STDERR_FILENO,
"Missing name for redirect.\n"), false);
ef->skip_i = ef->skip_i ?: i;
ef->skip_sz += 2;
node->vector.tokens[i + 1].str[node->vector.tokens[i + 1].sz] = '\0';
ef->rout_fd = open(node->vector.tokens[i + 1].str, O_CREAT | O_WRONLY |
(node->vector.tokens[i].type == T_APPEND ? O_APPEND : O_TRUNC), 0644);
if (ef->rout_fd < 0)
return (puterror(node->vector.tokens[i + 1].str), false);
ef->out_fd = ef->rout_fd;
return true;
}
bool handle_in_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz)
{
if (node->vector.tokens[i].type != T_IN_REDIRECT)
return true;
if (i >= sz || node->vector.tokens[i + 1].type != T_ARG)
return (WRITE_CONST(STDERR_FILENO,
"Missing name for redirect.\n"), false);
ef->skip_i = ef->skip_i ?: i;
ef->skip_sz += 2;
node->vector.tokens[i + 1].str[node->vector.tokens[i + 1].sz] = '\0';
ef->rin_fd = open(node->vector.tokens[i + 1].str, O_RDONLY);
if (ef->rin_fd < 0)
return (puterror(node->vector.tokens[i + 1].str), false);
ef->in_fd = ef->rin_fd;
return true;
}
int handle_heredoc_loop(ast_t *node, size_t i)
{
int fds[2];
buff_t buffer = { .str = NULL };
if (pipe(fds) < 0)
return (puterror("pipe"), -1);
node->vector.tokens[i + 1].str[node->vector.tokens[i + 1].sz] = '\0';
WRITE_CONST(STDOUT_FILENO, "? ");
while (getline(&buffer.str, &buffer.sz, stdin) != -1) {
buffer.str[u_strlen(buffer.str) - 1] = '\0';
if (u_strcmp(buffer.str, node->vector.tokens[i + 1].str) == 0)
break;
write(fds[1], buffer.str, u_strlen(buffer.str));
write(fds[1], "\n", 1);
WRITE_CONST(STDOUT_FILENO, "? ");
}
free(buffer.str);
close(fds[1]);
return fds[0];
}
bool handle_heredoc(ef_t *ef, ast_t *node, size_t i, size_t sz)
{
if (node->vector.tokens[i].type != T_HEREDOC)
return true;
if (i >= sz || node->vector.tokens[i + 1].type != T_ARG)
return (WRITE_CONST(STDERR_FILENO,
"Missing name for redirect.\n"), false);
ef->skip_i = ef->skip_i ?: i;
ef->skip_sz += 2;
ef->in_fd = handle_heredoc_loop(node, i);
if (ef->in_fd == -1)
return false;
return true;
}

View File

@@ -1,18 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef REDIRECTS_H
#define REDIRECTS_H
#include <stdbool.h>
#include "exec.h"
bool handle_out_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz);
bool handle_in_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz);
int handle_heredoc_loop(ast_t *node, size_t i);
bool handle_heredoc(ef_t *ef, ast_t *node, size_t i, size_t sz);
#endif /* REDIRECTS_H */

View File

@@ -1,86 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ast.h"
#include "common.h"
#include "debug.h"
#include "env.h"
#include "shell.h"
#include "u_str.h"
__attribute__((unused))
static
void debug_env_entries(env_t *env)
{
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
U_DEBUG("Env entry [%lu] [%s]\n", i, env->env[i]);
}
}
static
void check_basic_error(char const *buffer)
{
if (*buffer == '|')
WRITE_CONST(STDERR_FILENO, "Invalid null command.\n");
if (*buffer == '>' || *buffer == '<')
WRITE_CONST(STDERR_FILENO, "Missing name for redirect.\n");
}
static
void ignore_sigint(int sig __attribute__((unused)))
{
WRITE_CONST(STDIN_FILENO, "\n");
WRITE_CONST(STDOUT_FILENO, SHELL_PROMPT);
}
static
int shell_loop(env_t *env, int is_a_tty, history_t *history)
{
char *buffer = NULL;
size_t buffer_sz;
size_t buffer_len;
while (true) {
if (is_a_tty)
WRITE_CONST(STDOUT_FILENO, SHELL_PROMPT);
if (getline(&buffer, &buffer_sz, stdin) == -1)
break;
buffer_len = u_strlen(buffer);
if (buffer_len < 2 || !u_str_is_alnum(buffer)) {
check_basic_error(buffer);
continue;
}
buffer[buffer_len - 1] = '\0';
U_DEBUG("Buffer [%lu] [%s]\n", buffer_len, buffer);
visitor(buffer, env, history);
}
return (free(buffer), history->last_exit_code);
}
int shell(char **env_ptr)
{
env_t env = parse_env(env_ptr);
history_t history = { .cmd_history = NULL, 0, .last_chdir = NULL };
int shell_result;
if (!env.env)
return RETURN_FAILURE;
U_DEBUG_CALL(debug_env_entries, &env);
signal(SIGINT, ignore_sigint);
shell_result = shell_loop(&env, isatty(STDIN_FILENO), &history);
free_env(&env);
WRITE_CONST(STDOUT_FILENO, "exit\n");
return shell_result;
}

View File

@@ -1,19 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef SHELL_H
#define SHELL_H
#include "vt100_esc_codes.h"
#define SHELL_PROMPT RED "|> " RESET
typedef struct {
char **cmd_history;
int last_exit_code;
char *last_chdir;
} history_t;
int shell(char **env);
#endif /* SHELL_H */

View File

@@ -1,102 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <ctype.h>
#include "ast.h"
#include "debug.h"
#include "u_str.h"
const tokens_list_t TOKENS_LIST[] = {
{ T_SEMICOLON, ";", 1, "T_SEMICOLON" },
{ T_AND, "&&", 2, "T_AND" },
{ T_OR, "||", 2, "T_OR" },
{ T_PIPE, "|", 1, "T_PIPE" },
{ T_BACKTICK, "`", 1, "T_BACKTICK" },
{ T_LEFT_PARENT, "(", 1, "T_LEFT_PARENT" },
{ T_RIGHT_PARENT, ")", 1, "T_RIGHT_PARENT" },
{ T_PREV_CMD, "!!", 2, "T_PREV_CMD" },
{ T_APPEND, ">>", 2, "T_APPEND" },
{ T_REDIRECT, ">", 1, "T_REDIRECT" },
{ T_HEREDOC, "<<", 2, "T_HEREDOC" },
{ T_IN_REDIRECT, "<", 1, "T_IN_REDIRECT" },
{ T_EOF, "\0", 1, "T_EOF" }
};
const size_t TOKENS_LIST_SZ = sizeof TOKENS_LIST / sizeof *TOKENS_LIST;
static
void search_token(ast_ctx_t *ctx, int *found_token)
{
for (size_t i = 0; i < TOKENS_LIST_SZ; i++) {
if (u_strncmp(ctx->str, TOKENS_LIST[i].str, TOKENS_LIST[i].sz) == 0) {
*found_token = 1;
break;
}
}
}
static
void get_arg_token(ast_ctx_t *ctx, char **start, int *found_token,
size_t *arg_len)
{
char quote = 0;
if (*ctx->str == '\'' || *ctx->str == '"') {
quote = *ctx->str;
ctx->str++;
*start = ctx->str;
while (*ctx->str && *ctx->str != quote)
ctx->str++;
if (*ctx->str == quote) {
*arg_len = ctx->str - *start;
ctx->str++;
} else
*arg_len = ctx->str - *start;
*found_token = 1;
return;
}
search_token(ctx, found_token);
if (!*found_token)
ctx->str++;
}
static
int match_known_token(ast_ctx_t *ctx, token_t *token)
{
for (size_t i = 0; i < TOKENS_LIST_SZ; i++) {
if (u_strncmp(ctx->str, TOKENS_LIST[i].str, TOKENS_LIST[i].sz) == 0) {
U_DEBUG("Token %-14s [%.*s]\n", TOKENS_LIST[i].name,
(int)TOKENS_LIST[i].sz, ctx->str);
ctx->str += TOKENS_LIST[i].sz;
*token = (token_t){ TOKENS_LIST[i].type,
ctx->str - TOKENS_LIST[i].sz, TOKENS_LIST[i].sz };
return 1;
}
}
return 0;
}
token_t get_next_token(ast_ctx_t *ctx)
{
char *start;
int found_token = 0;
size_t arg_len = 0;
token_t token;
while (*ctx->str != '\0' && isblank(*ctx->str))
ctx->str++;
if (match_known_token(ctx, &token))
return token;
start = ctx->str;
while (*ctx->str && !isblank(*ctx->str) && !found_token)
get_arg_token(ctx, &start, &found_token, &arg_len);
if (arg_len == 0)
arg_len = ctx->str - start;
U_DEBUG("Token T_ARG [%.*s]\n", (int)arg_len, start);
return (token_t){ .type = T_ARG, .str = start, .sz = arg_len };
}

View File

@@ -1,164 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ast.h"
#include "builtins.h"
#include "common.h"
#include "exec.h"
#include "redirects.h"
#include "u_str.h"
/*
* ef->in_fd = ef->pin_fd;
* ef->out_fd = ef->out_fd;
* set used fds, to not close the wrong fd in visit pipe or handle redirect
*/
static
int visit_cmd(ef_t *ef)
{
int result;
ef->in_fd = ef->pin_fd;
ef->out_fd = ef->pout_fd;
ef->skip_i = 0;
ef->skip_sz = 0;
ef->rout_fd = 0;
ef->rin_fd = 0;
for (size_t i = 0; i < ef->act_node->vector.sz; i++) {
if (!handle_in_redirect(ef, ef->act_node, i, ef->act_node->vector.sz)
|| !handle_out_redirect(ef, ef->act_node, i, ef->act_node->vector.sz)
|| !handle_heredoc(ef, ef->act_node, i, ef->act_node->vector.sz))
return -1;
}
result = execute(ef);
if (ef->rout_fd)
close(ef->rout_fd);
if (ef->rin_fd)
close(ef->rin_fd);
return result;
}
static
int visit_pipe(ef_t *ef, size_t i, ast_t *node)
{
int result = RETURN_FAILURE;
if (i < node->list.sz - 1)
if (pipe(ef->pipes) < 0)
return (puterror("pipe"), -1);
ef->pout_fd = i == node->list.sz - 1 ? STDOUT_FILENO : ef->pipes[1];
ef->act_node = node->list.nodes[i];
if (!ef->act_node)
return -1;
result = visit_cmd(ef);
if (result == -1)
return RETURN_FAILURE;
if (ef->pin_fd != STDIN_FILENO)
close(ef->pin_fd);
if (i < node->list.sz - 1) {
close(ef->pipes[1]);
ef->pin_fd = ef->pipes[0];
}
return result;
}
static
int visit_pipes(ef_t *ef)
{
ast_t *node = ef->act_node;
int result = RETURN_FAILURE;
ef->p_i = 0;
ef->p_sz = node->list.sz;
ef->pin_fd = STDIN_FILENO;
ef->flags |= F_PIPE;
for (size_t i = 0; i < node->list.sz; i++) {
ef->p_i = i;
result = visit_pipe(ef, i, node);
if (result == -1)
break;
}
return result;
}
static
int visit_list(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
if (node->tok.type == T_PIPE) {
ef->act_node = node;
return visit_pipes(ef);
}
for (size_t i = 0; i < node->list.sz; i++) {
ef->flags &= ~F_PIPE;
ef->act_node = node->list.nodes[i];
if (node->list.nodes[i]->type == N_LST &&
node->list.nodes[i]->tok.type == T_PIPE)
result = visit_pipes(ef);
ef->pin_fd = STDIN_FILENO;
ef->pout_fd = STDOUT_FILENO;
if (node->list.nodes[i]->type == N_CMD)
result = visit_cmd(ef);
}
return result;
}
static
int visitor_launcher(ef_t *ef)
{
int result = RETURN_FAILURE;
ef->ctx->act_tok = get_next_token(ef->ctx);
ef->ctx->ast = parse_expression(ef->ctx);
if (ef->ctx->ast == NULL)
return RETURN_FAILURE;
if (ef->ctx->ast->type == N_LST)
result = visit_list(ef, ef->ctx->ast);
if (ef->ctx->ast->type == N_CMD) {
ef->act_node = ef->ctx->ast;
result = visit_cmd(ef);
}
return result;
}
static
void remove_trailing_semi(char *str)
{
for (size_t len = u_strlen(str); len > 0; len--) {
if (str[len] != '\0' && str[len] != '\n' && str[len] != ';')
break;
if (str[len] == ';')
str[len] = '\0';
}
}
int visitor(char *buffer, env_t *env, history_t *history)
{
ast_ctx_t ctx = { 0, .str = buffer, .cap = u_strlen(buffer) + 10,
.ast = malloc(sizeof *ctx.ast * (u_strlen(buffer) + 10)) };
ef_t ef = { .buffer = buffer, .env = env,
.history = history, .ctx = &ctx, .pout_fd = STDOUT_FILENO,
.flags = 0, 0 };
int result = RETURN_FAILURE;
ctx.first_node = ctx.ast;
remove_trailing_semi(ctx.str);
history->last_exit_code = 0;
if (ctx.ast == NULL)
return RETURN_FAILURE;
result = visitor_launcher(&ef);
if (ef.flags & F_EXIT)
builtins_exit(&ef, NULL);
free_ast(&ctx);
return result == -1 ? RETURN_FAILURE : result;
}

View File

@@ -1,27 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef CR_VT100_ESC_CODES_H
#define CR_VT100_ESC_CODES_H
#define ESC "\033"
#define CFMT(n) ESC "[" #n "m"
// move
#define MOVE_RIGHT(n) ESC "[" #n "C"
// colors
#define RESET CFMT(0)
#define BOLD CFMT(1)
#define RED CFMT(31)
#define GREEN CFMT(32)
#define YELLOW CFMT(33)
#define BLUE CFMT(34)
#define PURPLE CFMT(35)
#define CYAN CFMT(36)
#endif