Fix multi line

This commit is contained in:
savalet
2025-05-21 23:12:47 +02:00
parent d24143b3f5
commit ce0db9550f
80 changed files with 27 additions and 5538 deletions

2
FIX.md
View File

@@ -6,6 +6,6 @@
- [x] Alias loop
- [ ] All AFL crashes
- [ ] Fix CTRL+E and ->
- [ ] Multi line editing
- [x] Multi line editing
- [ ] Foreach in if
- [x] Output flushing when open an other shell with 42sh

View File

@@ -24,14 +24,6 @@ SRC += $(wildcard src/utils/*.c)
SRC += $(wildcard src/local/*.c)
SRC += $(wildcard src/repl/*.c)
BONUS_SRC := $(wildcard bonus/*.c)
BONUS_SRC += $(wildcard bonus/builtins/*.c)
BONUS_SRC += $(wildcard bonus/builtins/expr/*.c)
BONUS_SRC += $(wildcard bonus/ast/*.c)
BONUS_SRC += $(wildcard bonus/utils/*.c)
BONUS_SRC += $(wildcard bonus/local/*.c)
BONUS_SRC += $(wildcard bonus/repl/*.c)
LIB_SRC := $(wildcard ulib/*.c)
LIB_SRC += $(wildcard ulib/write/printf/*.c)
LIB_SRC += $(wildcard ulib/math/*.c)
@@ -91,7 +83,6 @@ $(eval $(call mk-profile, debug, SRC, -iquote src -D U_DEBUG_MODE \
-fanalyzer -g3, debug))
$(eval $(call mk-profile, test, SRC, -iquote src --coverage, test))
$(eval $(call mk-profile, afl, SRC, -iquote src -D AFL_MODE, afl_runner))
$(eval $(call mk-profile, bonus, BONUS_SRC, -iquote bonus, 42sh_job))
all: $(NAME_release)

View File

@@ -1,111 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** parse_alias
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "alias.h"
#include "common.h"
#include "history.h"
#include "utils.h"
static
int skip_blank(const char *buffer, int i)
{
for (; buffer[i] != 0 && isblank(buffer[i]); i++);
return i;
}
static
int skip_to_next_token(char *buffer, int i)
{
for (; buffer[i] != 0 && !is_a_token(buffer, i); i++);
return i;
}
static
char *find_alias(his_variable_t *variable, alias_t *alias, char *buffer)
{
char *cmd = malloc(sizeof(char) * (variable->size_variable + 1));
char *new_cmd = nullptr;
if (cmd == NULL)
return nullptr;
for (int i = variable->coord_variable; i !=
variable->coord_variable + variable->size_variable; i++)
cmd[i - variable->coord_variable] = buffer[i];
cmd[variable->size_variable] = '\0';
for (size_t i = 0; i != alias->size; i++){
if (alias->alias_array[i] == NULL)
return nullptr;
if (strcmp(cmd, alias->alias_array[i]) == 0){
new_cmd = cat_in_str(variable, buffer, alias->alias_to_replace[i]);
buffer = new_cmd;
}
}
free(cmd);
return new_cmd;
}
static
char *get_alias(char *buffer, int i, alias_t *alias)
{
int coord = i;
int size = 0;
his_variable_t variable = {0, 0, 0, nullptr, 0};
for (; buffer[i] != 0 && !isblank(buffer[i])
&& !is_a_token(buffer, i); i++)
size++;
variable.coord_variable = coord;
variable.size_variable = size;
buffer = find_alias(&variable, alias, buffer);
return buffer;
}
static
bool replace_alias(char **buffer, alias_t *alias)
{
char *tmp_buff = *buffer;
for (int i = skip_blank(tmp_buff, 0); tmp_buff[i] != 0; i++){
i = skip_blank(tmp_buff, i);
tmp_buff = get_alias(tmp_buff, i, alias);
if (tmp_buff == NULL)
return false;
i = skip_to_next_token(tmp_buff, i);
}
*buffer = tmp_buff;
return true;
}
int parse_alias(char **buffer, size_t *buffer_len, alias_t *alias)
{
bool need_to_replace = true;
while (need_to_replace)
need_to_replace = replace_alias(buffer, alias);
return RETURN_SUCCESS;
}
alias_t init_alias(void)
{
alias_t alias;
alias.size = 1;
alias.alias_array = malloc(sizeof(char *) * alias.size);
alias.alias_to_replace = malloc(sizeof(char *) * alias.size);
if (!alias.alias_array || !alias.alias_to_replace)
return alias;
alias.alias_array[0] = nullptr;
alias.alias_to_replace[0] = nullptr;
alias.size = 0;
return alias;
}

View File

@@ -1,21 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef ALIAS_H
#define ALIAS_H
#include <stddef.h>
typedef struct alias_s {
size_t size;
char **alias_array;
char **alias_to_replace;
} alias_t;
void free_alias(alias_t *alias);
int parse_alias(char **buffer, size_t *buffer_len, alias_t *alias);
alias_t init_alias(void);
#endif /* ALIAS*/

View File

@@ -1,90 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** globbing
*/
#include <glob.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "args.h"
#include "debug.h"
#include "exec.h"
#include "utils.h"
bool check_glob_result(int val, char *bin_name)
{
if (val != 0){
if (val == GLOB_NOMATCH)
dprintf(STDERR_FILENO, "%s: No match.\n", bin_name);
return false;
}
return true;
}
bool process_globbing(char *pattern, args_t *args, size_t *toks_i)
{
glob_t globs;
int glob_result;
char *vl;
U_DEBUG("Globbing pattern [%s]\n", pattern);
glob_result = glob(pattern, GLOB_ERR, nullptr, &globs);
if (!check_glob_result(glob_result, args->args[0]))
return false;
for (size_t i = 0; i < globs.gl_pathc; i++) {
ensure_args_capacity(args);
vl = strdup(globs.gl_pathv[i]);
if (vl == NULL)
return globfree(&globs), false;
args->args[args->sz] = vl;
args->sz++;
}
globfree(&globs);
return true;
}
static
bool handle_tilde(ef_t *ef, token_t *tok, args_t *args)
{
char *home;
char *final_str;
size_t tilde_pos = strcspn(tok->str, "~");
tok->str[tok->sz] = '\0';
home = get_env_value(ef->env, "HOME");
if (home != NULL)
final_str = get_env_value(ef->env, "HOME");
else
final_str = strdup("");
args->args[args->sz] = insert_str(tok->str, final_str, tilde_pos);
U_DEBUG("Tilde handling [%s] pos [%lu]\n", final_str, tilde_pos);
if (args->args[args->sz] == NULL)
return false;
args->sz++;
return true;
}
bool process_args(ast_t *node, args_t *args, size_t *toks_i, ef_t *ef)
{
token_t tok = node->vector.tokens[*toks_i];
if (!ensure_args_capacity(args))
return false;
if (tok.type == T_STAR) {
tok.str[tok.sz] = '\0';
return (process_globbing(tok.str, args, toks_i));
}
if (tok.type == T_TILDE)
return handle_tilde(ef, &tok, args);
handle_var_case(node, ef->exec_ctx, toks_i, args);
if (args->args[args->sz] == NULL)
return false;
args->sz++;
return true;
}

View File

@@ -1,24 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** globbing
*/
#ifndef GLOBBING_H
#define GLOBBING_H
#include <glob.h>
#include <stdbool.h>
#include "ast.h"
#include "exec.h"
typedef struct globs_s {
glob_t globs;
char **found_tab;
char **result_tab;
int val;
}globs_t;
bool process_args(ast_t *node, args_t *args, size_t *toks_i, ef_t *ef);
#endif /* GLOBBING_H */

View File

@@ -1,147 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef AST_H
#define AST_H
#include <stddef.h>
#include <stdint.h>
#include "ctx.h"
#define DEFAULT_AST_CAP 128
#define DEFAULT_N_LST_CAP 2
#define DEFAULT_N_CMD_CAP 2
#define DEFAULT_N_COND_CAP 2
#define T_ALL 0xff
typedef enum size_t {
T_SEMICOLON = 1 << 0, // ;
T_QUOTES = 1 << 1, // "
T_DQUOTES = 1 << 2, // "
T_AND = 1 << 3, // &&
T_OR = 1 << 4, // ||
T_PIPE = 1 << 5, // |
T_BACKTICK = 1 << 6, // `
T_LEFT_PARENT = 1 << 7, // (
T_RIGHT_PARENT = 1 << 8, // )
T_PREV_CMD = 1 << 9, // !!
T_VAR = 1 << 10, // $
T_REDIRECT = 1 << 11, // >
T_APPEND = 1 << 12, // >>
T_HEREDOC = 1 << 13, // <
T_IN_REDIRECT = 1 << 14, // <
T_AT = 1 << 15, // <
T_WHILE = 1 << 16, // while
T_STAR = 1 << 18, // *
T_BACKSLASH = 1 << 19,
T_NEWLINE = 1 << 20, // \n
T_TILDE = 1 << 21, // ~
T_EOF = 1 << 22, // \0
T_ARG = 1 << 23,
T_INVALID = 1 << 24
} token_type_t;
typedef enum {
N_LST,
N_CMD,
N_BIN,
N_LOP,
N_COND
} 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;
struct {
size_t sz;
size_t cap;
char **buffers;
ast_t *condition;
} loop;
struct {
ast_t *exp;
size_t sz;
size_t sz2;
size_t cap;
size_t cap2;
ast_t **nodes;
ast_t **nodes2;
} cond;
};
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;
size_t parsed_tok;
} ast_ctx_t;
extern const tokens_list_t TOKENS_LIST[];
// Main funcs
ast_t *parse_expression(ast_ctx_t *ctx);
token_t get_next_token(ast_ctx_t *ctx);
// Utils funcs
int visitor(char *buffer, exec_ctx_t *exec_ctx);
ast_t *create_node(ast_ctx_t *ctx);
bool ensure_node_cap(ast_t *node);
bool ensure_list_cap(ast_t *node);
bool ensure_cond_cap(ast_t *node);
bool ensure_cond_cap2(ast_t *node);
bool parser_eat(ast_ctx_t *ctx, token_type_t expected);
ast_t *parse_loop(ast_ctx_t *ctx);
void free_ast(ast_ctx_t *ctx);
void print_ast(ast_t *ast, ast_ctx_t *ctx, size_t depth);
void skip_semi(ast_ctx_t *ctx);
// Outside needed parser
ast_t *parse_cmd(ast_ctx_t *ctx);
ast_t *parse_semi(ast_ctx_t *ctx);
ast_t *parse_condition(ast_ctx_t *ctx);
ast_t *parse_and(ast_ctx_t *ctx, ast_t *l_node);
ast_t *parse_or(ast_ctx_t *ctx, ast_t *l_node);
ast_t *parse_if(ast_ctx_t *ctx);
ast_t *parse_condition_and(ast_ctx_t *ctx);
ast_t *parse_pipe(ast_ctx_t *ctx, ast_t *l_node);
#endif /* AST_H */

View File

@@ -1,192 +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
bool parse_special_args(ast_ctx_t *ctx)
{
if (memchr(ctx->act_tok.str, '~', ctx->act_tok.sz) != NULL)
ctx->act_tok.type = T_TILDE;
if (memchr(ctx->act_tok.str, '*', ctx->act_tok.sz) != NULL)
ctx->act_tok.type = T_STAR;
return true;
}
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 | T_NEWLINE))
return node;
if (!parse_special_args(ctx))
return nullptr;
if (ctx->act_tok.type == T_BACKSLASH) {
ctx->act_tok = get_next_token(ctx);
if (ctx->act_tok.type == T_EOF)
return node;
ctx->act_tok.type = T_ARG;
}
if (ctx->act_tok.type & (T_ARG | T_REDIRECT | T_APPEND |
T_IN_REDIRECT | T_HEREDOC | T_VAR | T_STAR | T_TILDE)) {
if (!ensure_node_cap(node))
return nullptr;
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 nullptr;
node->type = N_CMD;
node->vector.cap = DEFAULT_N_CMD_CAP;
node->vector.tokens =
malloc(sizeof *node->vector.tokens * node->vector.cap);
if (node->vector.tokens == NULL)
return nullptr;
if (!parse_special_args(ctx))
return nullptr;
node->tok = ctx->act_tok;
node->vector.tokens[0] = ctx->act_tok;
node->vector.sz = 1;
return parse_arg(ctx, node);
}
/*
* Removed this check to do && || if, nothing has changed,
* to be seen in case of trouble,
* putting it back this may solve the problem but will break the && || if
* if (ctx->act_tok.type == T_EOF)
* return ctx->ast;
*/
ast_t *parse_cmd(ast_ctx_t *ctx)
{
if (ctx->act_tok.type != T_ARG) {
if (ctx->act_tok.type & (T_WHILE))
return nullptr;
if (!parser_eat(ctx, T_ARG))
return nullptr;
}
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;
}
ast_t *parse_pipe(ast_ctx_t *ctx, ast_t *l_node)
{
ast_t *node = create_node(ctx);
if (node == NULL)
return nullptr;
node->type = N_LST;
node->tok = ctx->act_tok;
node->list.cap = DEFAULT_N_LST_CAP;
node->list.nodes = (ast_t **)malloc(sizeof(ast_t *) * node->list.cap);
if ((void *)node->list.nodes == NULL)
return nullptr;
node->list.sz = 1;
node->list.nodes[0] = l_node;
if (!parser_eat(ctx, T_ARG))
return nullptr;
while (ctx->act_tok.type & (T_ARG | T_PIPE))
if (!parse_pipe_childs(ctx, node))
return nullptr;
return node;
}
ast_t *parse_semi(ast_ctx_t *ctx)
{
ast_t *l_node = parse_condition_and(ctx);
if (l_node == NULL)
return nullptr;
if (ctx->act_tok.type == T_OR) {
ctx->ast = parse_or(ctx, l_node);
return ctx->ast;
}
return l_node;
}
static
ast_t *create_semi_node(ast_ctx_t *ctx, ast_t *l_node)
{
ast_t *node = create_node(ctx);
if (node == NULL)
return nullptr;
node->type = N_LST;
node->list.cap = DEFAULT_N_LST_CAP;
node->list.nodes = (ast_t **)malloc(sizeof(ast_t *) * node->list.cap);
if ((void *)node->list.nodes == NULL)
return nullptr;
node->list.sz = 1;
node->list.nodes[0] = l_node;
node->tok = ctx->act_tok;
return node;
}
static
ast_t *fill_semi_node(ast_ctx_t *ctx, ast_t *node)
{
while (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE)) {
ctx->act_tok = get_next_token(ctx);
if (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE))
continue;
if (!ensure_list_cap(node))
return nullptr;
node->list.nodes[node->list.sz] = parse_semi(ctx);
if (node->list.nodes[node->list.sz] == NULL)
return nullptr;
node->list.sz++;
}
return node;
}
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;
ctx->act_tok = get_next_token(ctx);
skip_semi(ctx);
l_node = parse_semi(ctx);
if (l_node == NULL)
return ctx->ast;
if (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE)) {
node = create_semi_node(ctx, l_node);
if (node == NULL)
return nullptr;
ctx->ast = fill_semi_node(ctx, node);
}
return parse_expression(ctx);
}

View File

@@ -1,75 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include "ast.h"
#include "u_mem.h"
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->list.cap)
return true;
temp = (ast_t **)u_realloc((void *)node->list.nodes,
sizeof *node->list.nodes * node->list.sz,
sizeof *node->list.nodes * node->list.cap << 1);
if ((void *)temp == NULL)
return false;
node->list.cap <<= 1;
node->list.nodes = temp;
return true;
}
bool ensure_cond_cap(ast_t *node)
{
ast_t **temp;
if (node->cond.sz + 1 < node->cond.cap)
return true;
temp = (ast_t **)u_realloc((void *)node->cond.nodes,
sizeof *node->cond.nodes * node->cond.sz,
sizeof *node->cond.nodes * node->cond.cap << 1);
if ((void *)temp == NULL)
return false;
node->cond.cap <<= 1;
node->cond.nodes = temp;
return true;
}
bool ensure_cond_cap2(ast_t *node)
{
ast_t **temp;
if (node->cond.sz2 + 1 < node->cond.cap2)
return true;
temp = (ast_t **)u_realloc((void *)node->cond.nodes2,
sizeof *node->cond.nodes2 * node->cond.sz2,
sizeof *node->cond.nodes2 * node->cond.cap2 << 1);
if ((void *)temp == NULL)
return false;
node->cond.cap2 <<= 1;
node->cond.nodes2 = temp;
return true;
}

View File

@@ -1,65 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ast.h"
#include "u_mem.h"
void print_ast(ast_t *ast, ast_ctx_t *ctx, size_t depth)
{
for (size_t i = 0; i < depth; i++)
fprintf(stderr, " ");
if (depth)
fprintf(stderr, "- ");
fprintf(stderr, "(%.*s)\n", (int)ast->tok.sz, ast->tok.str);
if (ast->type == N_BIN) {
print_ast(ast->binary.left, ctx, depth + 1);
print_ast(ast->binary.right, ctx, depth + 1);
}
if (ast->type == N_CMD) {
for (size_t i = 1; i < ast->vector.sz; i++)
fprintf(stderr, "%*s - (%.*s)\n", (int)depth, "",
(int)ast->vector.tokens[i].sz, ast->vector.tokens[i].str);
}
if (ast->type == N_LST) {
for (size_t i = 0; i < ast->list.sz; i++)
print_ast(ast->list.nodes[i], ctx, depth + 1);
}
}
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;
}
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,148 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ast.h"
#include "common.h"
#include "u_str.h"
ast_t *parse_and(ast_ctx_t *ctx, ast_t *l_node)
{
ast_t *node = create_node(ctx);
if (node == NULL || l_node == NULL)
return nullptr;
node->tok = ctx->act_tok;
node->type = N_BIN;
node->binary.left = l_node;
node->binary.right = parse_condition_and(ctx);
if (node->binary.right == NULL)
return nullptr;
return node;
}
ast_t *parse_or(ast_ctx_t *ctx, ast_t *l_node)
{
ast_t *node = create_node(ctx);
if (node == NULL || l_node == NULL)
return nullptr;
node->tok = ctx->act_tok;
node->type = N_BIN;
node->binary.left = l_node;
node->binary.right = parse_semi(ctx);
if (node->binary.right == NULL)
return nullptr;
return node;
}
ast_t *parse_condition_and(ast_ctx_t *ctx)
{
ast_t *l_node = parse_condition(ctx);
if (l_node == NULL)
return nullptr;
if (ctx->act_tok.type == T_AND) {
ctx->ast = parse_and(ctx, l_node);
return ctx->ast;
}
return l_node;
}
ast_t *parse_condition(ast_ctx_t *ctx)
{
ast_t *l_node = parse_cmd(ctx);
if (l_node == NULL)
return nullptr;
switch (ctx->act_tok.type) {
case T_PIPE:
ctx->ast = parse_pipe(ctx, l_node);
break;
default:
return l_node;
}
return ctx->ast;
}
static
bool fill_else_node(ast_ctx_t *ctx, ast_t *node, buff_t *buff)
{
ctx->str = buff->str;
node->cond.nodes2[node->cond.sz2] = parse_semi(ctx);
if (node->cond.nodes2[node->cond.sz2] == NULL)
return false;
node->cond.sz2++;
return ensure_cond_cap2(node);
}
static
bool fill_if_node(ast_ctx_t *ctx, ast_t *node, bool fill_else, buff_t *buff)
{
if (strncmp(buff->str, "else", 4) == 0)
return true;
if (fill_else)
return fill_else_node(ctx, node, buff);
ctx->str = buff->str;
node->cond.nodes[node->cond.sz] = parse_semi(ctx);
if (node->cond.nodes[node->cond.sz] == NULL)
return false;
node->cond.sz++;
return ensure_cond_cap(node);
}
static
ast_t *fill_if(ast_ctx_t *ctx, ast_t *node)
{
buff_t buff = { .str = nullptr, 0 };
char *old_buff = ctx->str;
bool fill_else = false;
while (true) {
if (isatty(STDIN_FILENO))
WRITE_CONST(STDOUT_FILENO, IF_PROMPT);
if (getline(&buff.str, &buff.sz, stdin) < 0)
return nullptr;
buff.str[strlen(buff.str) - 1] = '\0';
if (strncmp(buff.str, "endif", 5) == 0)
break;
if (strncmp(buff.str, "else", 4) == 0)
fill_else = true;
if (!fill_if_node(ctx, node, fill_else, &buff))
return nullptr;
buff = (buff_t){ .str = nullptr, 0 };
}
ctx->str = old_buff;
return node;
}
ast_t *parse_if(ast_ctx_t *ctx)
{
ast_t *node = create_node(ctx);
if (node == NULL)
return nullptr;
node->tok = ctx->act_tok;
node->type = N_COND;
node->cond.cap = DEFAULT_N_COND_CAP;
node->cond.cap2 = DEFAULT_N_COND_CAP;
memset(&node->cond.sz, 0, sizeof node->cond.sz * 2);
node->cond.nodes =
(ast_t **)malloc(sizeof *node->cond.nodes * node->cond.cap);
node->cond.nodes2 =
(ast_t **)malloc(sizeof *node->cond.nodes * node->cond.cap2);
if ((void *)node->cond.nodes == NULL || (void *)node->cond.nodes2 == NULL)
return nullptr;
node->cond.exp = parse_semi(ctx);
if (node->cond.exp == NULL)
return WRITE_CONST(STDERR_FILENO, "if: Too few arguments.\n"), NULL;
return fill_if(ctx, node);
}

View File

@@ -1,175 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <ctype.h>
#include <unistd.h>
#include "ast.h"
#include "debug.h"
#include "u_str.h"
const tokens_list_t TOKENS_LIST[] = {
{ T_SEMICOLON, ";", 1, "T_SEMICOLON" },
{ T_QUOTES, "\'", 1, "T_QUOTES"},
{ T_DQUOTES, "\"", 1, "T_DQUOTES"},
{ 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_BACKSLASH, "\\", 1, "T_BACKSLASH" },
{ T_NEWLINE, "\n", 1, "T_NEWLINE"},
{ T_EOF, "\0", 1, "T_EOF" }
};
const size_t TOKENS_LIST_SZ = sizeof TOKENS_LIST / sizeof *TOKENS_LIST;
const tokens_list_t CLOSABLE[] = {
{ T_RIGHT_PARENT, ")", 1, "T_RIGHT_PARENT" },
{ T_LEFT_PARENT, "(", 1, "T_LEFT_PARENT" },
{ T_BACKTICK, "`", 1, "T_BACKTICK" },
{ T_QUOTES, "\'", 1, "T_QUOTES"},
{ T_DQUOTES, "\"", 1, "T_DQUOTES"}
};
const size_t CLOSABLE_LIST_SZ = sizeof CLOSABLE / sizeof *CLOSABLE;
void skip_semi(ast_ctx_t *ctx)
{
while (ctx->act_tok.type == T_SEMICOLON)
ctx->act_tok = get_next_token(ctx);
}
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
dprintf(STDERR_FILENO, "Parse error near \"%.*s\"\n",
(int)ctx->ast->tok.sz, ctx->ast->tok.str);
return false;
}
return true;
}
static
bool check_closable(token_t actual_token)
{
if (actual_token.type == 0)
return false;
for (size_t i = 0; i < CLOSABLE_LIST_SZ; i++) {
if (actual_token.type == CLOSABLE[i].type)
return true;
}
return false;
}
static
token_t handle_token_type(ast_ctx_t *ctx)
{
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;
return (token_t){ TOKENS_LIST[i].type,
ctx->str - TOKENS_LIST[i].sz, TOKENS_LIST[i].sz };
}
}
return (token_t){0, NULL, 0};
}
static
bool compare_to_close(ast_ctx_t *ctx, token_t acutal_tok)
{
token_type_t token = 0;
if (!*ctx->str && !(*ctx->str + 1))
return false;
for (size_t i = 0; i < TOKENS_LIST_SZ; i++) {
if (u_strncmp(ctx->str, TOKENS_LIST[i].str,
TOKENS_LIST[i].sz) == 0) {
token = TOKENS_LIST[i].type;
break;
}
}
if (u_strncmp(ctx->str, acutal_tok.str, acutal_tok.sz) == 0){
if (acutal_tok.type & (T_QUOTES | T_DQUOTES)
&& !isblank(*(ctx->str + 1)) && token == 0)
return false;
return true;
}
return false;
}
static
void get_arg_token(ast_ctx_t *ctx, int *found_token, token_t acutal_tok)
{
if (check_closable(acutal_tok)){
ctx->str++;
if (compare_to_close(ctx, acutal_tok)){
*found_token = 1;
ctx->str++;
}
return;
}
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;
}
}
if (!*found_token)
ctx->str++;
}
void format_for_closable(ast_ctx_t *ctx, token_t *actual_token)
{
if (actual_token->type == T_RIGHT_PARENT)
*actual_token = handle_token_type(ctx);
if (actual_token->type == T_LEFT_PARENT &&
ctx->parsed_tok == 1)
*actual_token = (token_t){ 0, NULL, 0 };
if (actual_token->type == T_LEFT_PARENT
&& ctx->parsed_tok != 1)
*actual_token = (token_t){ T_RIGHT_PARENT, ")", 1};
if (check_closable(*actual_token))
ctx->str -= actual_token->sz;
}
token_t get_next_token(ast_ctx_t *ctx)
{
char *start;
int found_token = 0;
token_t actual_token;
ctx->parsed_tok++;
while (*ctx->str != '\0' && isblank(*ctx->str))
ctx->str++;
actual_token = handle_token_type(ctx);
format_for_closable(ctx, &actual_token);
if (actual_token.type != 0 && !check_closable(actual_token))
return actual_token;
start = ctx->str;
while ((*ctx->str && !found_token && (!isblank(*ctx->str) ||
check_closable(actual_token))))
get_arg_token(ctx, &found_token, actual_token);
U_DEBUG("Token T_ARG [%.*s]\n", (int)(ctx->str - start), start);
return (token_t){ .type = T_ARG, .str = start,
.sz = (size_t)(ctx->str - start) };
}

View File

@@ -1,56 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef BUILTINS_H
#define BUILTINS_H
#include "exec.h"
#include "u_str.h"
typedef struct {
char **cmds;
size_t size;
size_t cap;
} cmd_block_t;
typedef struct {
buff_t *buff;
bool in_else;
ef_t *ef;
} if_ctx_t;
typedef struct {
char const *name;
int (*ptr)(ef_t *ef, char **args);
} builtins_funcs_t;
extern const builtins_funcs_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);
int builtins_history(ef_t *ef, char **args);
int builtins_alias(ef_t *ef, char **args);
int builtins_display_alias(alias_t *alias);
int builtins_repeat(ef_t *ef, char **args);
int builtins_yes(ef_t *ef, char **args);
int builtins_foreach(ef_t *ef, char **args);
int builtins_while(ef_t *ef, char **args);
int builtins_set(ef_t *ef, char **args);
int builtins_unset(ef_t *ef, char **args);
int builtins_where(ef_t *ef, char **args);
int builtins_which(ef_t *ef, char **args);
int builtins_break(ef_t *ef, char **args);
int builtins_expr(ef_t *ef, char **args);
int builtins_if(ef_t *ef, char **args);
int builtins_fg(ef_t *ef, char **args);
#endif /* BUILTIND_H */

View File

@@ -1,33 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** break
*/
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include "ast.h"
#include "builtins.h"
#include "common.h"
#include "exec.h"
#include "u_str.h"
bool checking_error(ef_t *ef, char **args)
{
if (args[1])
return (WRITE_CONST(STDERR_FILENO, "break: Too many arguments.\n"),
RETURN_FAILURE);
if (!ef->exec_ctx->local->in_a_loop)
return (WRITE_CONST(STDERR_FILENO, "break: Not in while/foreach.\n"),
RETURN_FAILURE);
return RETURN_SUCCESS;
}
int builtins_break(ef_t *ef, char **args)
{
if (ef->exec_ctx->local->in_a_loop)
exit(checking_error(ef, args));
return checking_error(ef, args);
}

View File

@@ -1,172 +0,0 @@
/*
** EPITECH PROJECT, 2025
** history_42sh
** File description:
** builtin_history
*/
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "history.h"
#include "u_str.h"
#include "utils.h"
/*
**Il faut deux \0 parce que dans le gettokeniser
** y un truc qui regarde
**après le premier \0
*/
/*
**cat in str prend un
** his_variable_t en
** parametre pour
** connaitre la coord
** d' ou commencer a concaténer
** mais aussi le nombre de charactère a retiré
** il vas free le buffer
*/
static char *concat_cmd_arg(char *dest, char *src)
{
int l;
int i;
char *r_value = nullptr;
if (!src) {
r_value = u_strdup(dest);
return r_value;
}
l = strlen(dest);
i = strlen(src);
r_value = malloc(sizeof(char)* (i + l + 2));
if (r_value != NULL) {
strcpy(r_value, dest);
r_value[l] = ' ';
r_value[l +1] = '\0';
strcat(r_value, src);
}
return r_value;
}
char *his_last_command(char *line,
his_variable_t *his_variable, his_command_t *his_command)
{
char *new_line = nullptr;
char *new_str = nullptr;
if (his_command->sz == 0){
fprintf(stderr, "%d: Event not found.\n", his_command->sz);
return nullptr;
}
new_line = concat_cmd_arg(his_command[his_command->sz - 1].command,
his_command[his_command->sz - 1].arg);
new_str = cat_in_str(his_variable, line, new_line);
printf("%s\n", new_line);
return new_str;
}
char *his_last_same_command(char *line,
his_variable_t *his_variable, his_command_t *his_command)
{
char *new_line = &line[his_variable->coord_variable + 1];
char *new_str = nullptr;
for (int i = his_command->sz - 1; i > 0; i--) {
if (his_command[i].command == NULL) {
fprintf(stderr, "%s: Event not found.\n", new_line);
return new_str;
}
if (strncmp(his_command[i].command, new_line, strlen(new_line)) == 0) {
new_line = concat_cmd_arg(his_command[i].command,
his_command[i].arg);
new_str = cat_in_str(his_variable, line, new_line);
free(line);
return new_str;
}
}
fprintf(stderr, "%s: Event not found.\n", new_line);
return new_str;
}
char *his_id_command(char *line,
his_variable_t *his_variable, his_command_t *his_command)
{
int id = -1 + atoi(&line[his_variable->coord_variable + 1]);
char *new_line;
char *new_str = nullptr;
if (id < 0 || id > 100 || his_command[id].command == NULL){
fprintf(stderr, "%d: Event not found.\n", id + 1);
return new_str;
}
new_line = concat_cmd_arg(his_command[id].command, his_command[id].arg);
new_str = cat_in_str(his_variable, line, new_line);
printf("%s\n", new_str);
free(new_line);
free(line);
return new_str;
}
static char *get_last_word(char *str)
{
char *last_word = nullptr;
int last_space = 0;
int x = 0;
if (!str)
return nullptr;
while (str[x] != '\0') {
if (isblank(str[x]))
last_space = x + 1;
x++;
}
last_word = malloc(sizeof(char) * ((x - last_space) + 1));
if (last_word != NULL) {
last_word = strncpy(last_word, &str[last_space], x - last_space);
last_word[x - last_space] = '\0';
}
return last_word;
}
char *his_last_word(char *line,
his_variable_t *his_variable, his_command_t *his_command)
{
char *new_line = nullptr;
char *new_str = nullptr;
if (his_command[his_command->sz - 1].arg == NULL){
new_line = get_last_word(his_command[his_command->sz - 1].command);
} else
new_line = get_last_word(his_command[his_command->sz - 1].arg);
if (!new_line)
return nullptr;
new_str = cat_in_str(his_variable, line, new_line);
printf("%s\n", new_str);
free(new_line);
free(line);
return new_str;
}
char *his_last_arg(char *line,
his_variable_t *his_variable, his_command_t *his_command)
{
int id = his_command->sz - 1;
char *new_line = nullptr;
char *new_str = nullptr;
if (!his_command[id].arg)
new_line = " ";
else
new_line = u_strdup(his_command[id].arg);
new_str = cat_in_str(his_variable, line, new_line);
printf("%s\n", new_line);
if (his_command[id].arg)
free(new_line);
free(line);
return new_str;
}

View File

@@ -1,23 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdlib.h>
#include <unistd.h>
#include "builtins.h"
#include "common.h"
#include "exec.h"
#include "u_str.h"
int builtins_builtins(ef_t *ef, char **args[[gnu::unused]])
{
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;
}

View File

@@ -1,124 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** history
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alias.h"
#include "common.h"
#include "exec.h"
#include "utils.h"
void free_alias(alias_t *alias)
{
for (size_t i = 0; i != alias->size; i++){
free(alias->alias_array[i]);
free(alias->alias_to_replace[i]);
}
free(alias->alias_array);
free(alias->alias_to_replace);
return;
}
int builtins_display_alias(alias_t *alias)
{
for (size_t i = 0; i != alias->size; i++){
printf("|| Alias: %s || ", alias->alias_array[i]);
printf("Command: %s ||\n", alias->alias_to_replace[i]);
}
return RETURN_SUCCESS;
}
static
int size_str_in_narray(int i, char **array)
{
int size_str = 0;
for (int cp_i = i; array[cp_i] != NULL; cp_i++)
size_str += strlen(array[cp_i]) + 1;
return size_str;
}
static
char *array_nto_strdup(char **array, int i)
{
char *new_str = NULL;
int size_str = 0;
int letter = 0;
if (len_array(array) < i)
return NULL;
size_str = size_str_in_narray(i, array);
new_str = malloc(size_str + 1);
if (new_str == NULL)
return NULL;
for (int j = i; array[j] != NULL; j++){
for (int k = 0; array[j][k] != '\0'; k++){
new_str[letter] = array[j][k];
letter++;
}
new_str[letter] = ' ';
letter++;
}
new_str[letter] = '\0';
return new_str;
}
static
int add_alias_array(alias_t *alias, char **args)
{
char **new_alias_array =
realloc(alias->alias_array, sizeof(char *) * alias->size);
char **new_replace =
realloc(alias->alias_to_replace, sizeof(char *) * alias->size);
if (!new_alias_array || !new_replace){
free(new_alias_array);
free(new_replace);
return RETURN_FAILURE;
}
alias->alias_array = new_alias_array;
alias->alias_to_replace = new_replace;
alias->alias_array[alias->size - 1] = strdup(args[1]);
alias->alias_to_replace[alias->size - 1] = array_nto_strdup(args, 2);
return RETURN_SUCCESS;
}
int add_alias(alias_t *alias, char **args)
{
int replace = -1;
for (size_t i = 0; i != alias->size - 1; i++)
if (!strcmp(args[1], alias->alias_array[i]))
replace = (int)(i);
if (replace == -1)
return add_alias_array(alias, args);
alias->size--;
free(alias->alias_to_replace[replace]);
alias->alias_to_replace[replace] = array_nto_strdup(args, 2);
return RETURN_SUCCESS;
}
int builtins_alias(ef_t *ef, char **args)
{
alias_t *alias = ef->exec_ctx->alias;
char *first_arg = args[1];
if (first_arg != NULL && strcmp(args[1], "-h") == 0){
fprintf(stderr, "alias [cpy] [command]\n");
return RETURN_FAILURE;
}
if (len_array(args) < 3){
builtins_display_alias(alias);
return RETURN_SUCCESS;
}
alias->size++;
if (add_alias(alias, args) == RETURN_FAILURE)
return RETURN_FAILURE;
return RETURN_SUCCESS;
}

View File

@@ -1,95 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#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"
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 nullptr;
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->exec_ctx->history->last_chdir != NULL && args[1] != NULL
&& u_strcmp(args[1], "-") == 0)
path = ef->exec_ctx->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->exec_ctx->history->last_chdir);
ef->exec_ctx->history->last_chdir = act_pwd;
set_env(ef->env, "PWD", path);
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)
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,55 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include "env.h"
#include "exec.h"
#include "u_str.h"
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);
for (int i = 0; args[i]; i++)
unset_env(ef->env, args[1]);
return RETURN_SUCCESS;
}

View File

@@ -1,27 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include "env.h"
#include "exec.h"
int builtins_exit(ef_t *ef, char **args[[gnu::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);
exit(ef->exec_ctx->history->last_exit_code);
}

View File

@@ -1,51 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef EXPR_H
#define EXPR_H
#include <stdbool.h>
#include <stddef.h>
#define FIRST_TOKEN_BATCH_SIZE 64
#define IS_CHAR(s, c) ((s)[0] == (c) && (s)[1] == '\0')
#define COUNT_OF(arr) (sizeof (arr) / (sizeof *(arr)))
typedef unsigned char uchar_t;
typedef enum {
E_VAL_INT = 'd',
E_VAL_STR = 's',
E_VAL_ERR = 'e',
} expr_val_type_t;
typedef struct {
char *p;
union {
long val;
char const *str;
};
char type;
} expr_val_t;
typedef struct {
char name[4];
unsigned int prec;
expr_val_t (*apply)(expr_val_t *, expr_val_t *);
} expr_op_precedence_t;
typedef struct {
char **args;
} expr_state_t;
expr_val_t expr_run(expr_state_t *state, uchar_t depth, int prec);
extern const expr_op_precedence_t OPERATOR_PRECEDENCE[];
extern const size_t OPERATOR_PRECEDENCE_COUNT;
#endif

View File

@@ -1,138 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdio.h>
#include <string.h>
#include "expr.h"
static
expr_val_t apply_add(expr_val_t *left, expr_val_t *right)
{
expr_val_t res;
if (left->type != E_VAL_INT || right->type != E_VAL_INT) {
res.str = "non-integer argument";
res.type = E_VAL_ERR;
} else {
res.val = left->val + right->val;
res.type = E_VAL_INT;
}
return res;
}
static
expr_val_t apply_sub(expr_val_t *left, expr_val_t *right)
{
expr_val_t res;
if (left->type != E_VAL_INT || right->type != E_VAL_INT) {
res.str = "non-integer argument";
res.type = E_VAL_ERR;
} else {
res.val = left->val - right->val;
res.type = E_VAL_INT;
}
return res;
}
static
expr_val_t apply_mul(expr_val_t *left, expr_val_t *right)
{
expr_val_t res;
if (left->type != E_VAL_INT || right->type != E_VAL_INT) {
res.str = "non-integer argument";
res.type = E_VAL_ERR;
} else {
res.val = left->val * right->val;
res.type = E_VAL_INT;
}
return res;
}
static
expr_val_t apply_div(expr_val_t *left, expr_val_t *right)
{
expr_val_t res = { .type = E_VAL_ERR };
if (left->type != E_VAL_INT || right->type != E_VAL_INT) {
res.str = "non-integer argument";
res.type = E_VAL_ERR;
return res;
}
if (right->val == 0) {
res.str = "division by zero";
res.type = E_VAL_ERR;
return res;
}
res.val = left->val / right->val;
res.type = E_VAL_INT;
return res;
}
static
expr_val_t apply_lt(expr_val_t *left, expr_val_t *right)
{
expr_val_t res = { .type = E_VAL_INT };
if (left->type == E_VAL_INT && right->type == E_VAL_INT)
res.val = left->val < right->val;
else
res.val = strcmp(left->p, right->p) < 0;
return res;
}
static
expr_val_t apply_gt(expr_val_t *left, expr_val_t *right)
{
expr_val_t res = { .type = E_VAL_INT };
if (left->type == E_VAL_INT && right->type == E_VAL_INT)
res.val = left->val > right->val;
else
res.val = strcmp(left->p, right->p) > 0;
return res;
}
static
expr_val_t apply_eq(expr_val_t *left, expr_val_t *right)
{
expr_val_t res = { .type = E_VAL_INT };
if (left->type == E_VAL_INT && right->type == E_VAL_INT)
res.val = left->val == right->val;
else
res.val = !strcmp(left->p, right->p);
return res;
}
static
expr_val_t apply_neq(expr_val_t *left, expr_val_t *right)
{
expr_val_t res = { .type = E_VAL_INT };
if (left->type == E_VAL_INT && right->type == E_VAL_INT)
res.val = left->val != right->val;
else
res.val = strcmp(left->p, right->p);
return res;
}
const expr_op_precedence_t OPERATOR_PRECEDENCE[] = {
{ .name = "+", .prec = 2, apply_add },
{ .name = "-", .prec = 2, apply_sub },
{ .name = "*", .prec = 3, apply_mul },
{ .name = "/", .prec = 3, apply_div },
{ .name = "<", .prec = 1, apply_lt },
{ .name = ">", .prec = 1, apply_gt },
{ .name = "=", .prec = 1, apply_eq },
{ .name = "==", .prec = 1, apply_eq },
{ .name = "!=", .prec = 1, apply_neq },
};
const size_t OPERATOR_PRECEDENCE_COUNT = COUNT_OF(OPERATOR_PRECEDENCE);

View File

@@ -1,100 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "expr.h"
static
const expr_op_precedence_t *op_precedence(char *op)
{
for (size_t i = 0; i < OPERATOR_PRECEDENCE_COUNT; i++)
if (!strcmp(op, OPERATOR_PRECEDENCE[i].name))
return OPERATOR_PRECEDENCE + i;
return NULL;
}
static
expr_val_t expr_parse_paren(expr_state_t *state, uchar_t depth)
{
expr_val_t out;
state->args++;
out = expr_run(state, depth, 0);
if (out.type == E_VAL_ERR)
return out;
if (*state->args == NULL || !IS_CHAR(*state->args, ')')) {
out.str = "syntax error: missing ')'";
out.type = E_VAL_ERR;
return out;
}
state->args++;
return out;
}
static
void expr_solve_precedence(
expr_val_t *out,
expr_state_t *state, uchar_t depth, unsigned int prec)
{
const expr_op_precedence_t *op_prec;
expr_val_t tmp;
while (*state->args != NULL && !IS_CHAR(*state->args, ')')) {
op_prec = op_precedence(*state->args);
if (op_prec == NULL) {
out->type = E_VAL_ERR;
out->str = "syntax error: unexpected argument";
break;
}
if (op_prec->prec == 0 || op_prec->prec <= prec)
return;
state->args++;
tmp = expr_run(state, depth, op_prec->prec);
if (tmp.type == E_VAL_ERR) {
*out = tmp;
break;
}
*out = op_prec->apply(out, &tmp);
}
}
expr_val_t expr_parse_val(expr_state_t *state)
{
expr_val_t out;
char *chk;
out.val = strtol(*state->args, &chk, 10);
out.p = *state->args;
if (chk != *state->args && *chk == '\0')
out.type = E_VAL_INT;
else
out.type = E_VAL_STR;
state->args++;
return out;
}
expr_val_t expr_run(expr_state_t *state, uchar_t depth, int prec)
{
expr_val_t out = {
.type = E_VAL_ERR,
.str = "syntax error: missing argument"
};
if (*state->args == NULL)
return out;
if (IS_CHAR(*state->args, '('))
out = expr_parse_paren(state, depth + 1);
else
out = expr_parse_val(state);
expr_solve_precedence(&out, state, depth, prec);
return out;
}

View File

@@ -1,37 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "exec.h"
#include "expr.h"
int builtins_expr(ef_t *ef[[gnu::unused]], char **args)
{
int argc = 0;
expr_state_t state;
expr_val_t ret;
for (; args[argc] != nullptr; argc++);
if (argc < 2)
return fprintf(stderr, "%s: missing operand\nTry 'expr --help' for"
" more information.", args[0]), -1;
state = (expr_state_t){ .args = &args[1] };
ret = expr_run(&state, 0, 0);
if (ret.type == E_VAL_ERR)
return printf("%s: %s\n", args[0], ret.str), -1;
if (ret.type == E_VAL_INT && (strcmp("if", args[0]) == 0 ||
strcmp("while", args[0]) == 0))
return ret.val;
if (ret.type == E_VAL_INT)
printf("%ld\n", ret.val);
if (ret.type == E_VAL_STR)
printf("%s\n", ret.p);
return RETURN_SUCCESS;
}

View File

@@ -1,27 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <unistd.h>
#include "common.h"
#include "exec.h"
#include "job.h"
int builtins_fg(ef_t *ef, char **args)
{
int status;
if (!set_child_fg(ef->exec_ctx, ef->exec_ctx->jobs.sz - 1))
return RETURN_FAILURE;
waitpid(ef->exec_ctx->jobs.jobs[ef->exec_ctx->jobs.sz - 1].pgid, &status,
WUNTRACED);
if (WIFEXITED(status))
ef->exec_ctx->history->last_exit_code =
ef->exec_ctx->history->last_exit_code ?: WEXITSTATUS(status);
tcsetpgrp(ef->exec_ctx->read_fd, ef->exec_ctx->jobs.jobs[0].pgid);
return RETURN_SUCCESS;
}

View File

@@ -1,17 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <unistd.h>
#include "common.h"
#include "exec.h"
int builtins_funny_double_dot(ef_t *c[[gnu::unused]],
char **args[[gnu::unused]])
{
return RETURN_SUCCESS;
}

View File

@@ -1,101 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** get_loop_cmd
*/
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include "common.h"
#include "loop.h"
#include "repl.h"
#include "u_mem.h"
#include "u_str.h"
static
usr_cmd_t *buffers_realloc(usr_cmd_t *usr)
{
char **new_buffers = (char **)u_realloc((void *)usr->cmds, sizeof
*usr->cmds * usr->sz, sizeof
*usr->cmds * (usr->cap << 1));
if ((void *)new_buffers == NULL)
return nullptr;
usr->cmds = new_buffers;
usr->cap <<= 1;
return usr;
}
static
usr_cmd_t *increase_buffers(usr_cmd_t *usr, size_t *buffer_len)
{
usr->cmds[usr->sz] = nullptr;
getline(&(usr->cmds[usr->sz]), buffer_len, stdin);
*buffer_len = u_strlen(usr->cmds[usr->sz]);
usr->cmds[usr->sz][*buffer_len - 1] = '\0';
usr->sz++;
return usr;
}
static
usr_cmd_t *handle_end(usr_cmd_t *us, char const *prompt)
{
us->sz--;
if (!us->cmds[us->sz] || strcmp("end", us->cmds[us->sz]) != 0){
printf("%s: end not found.\n", prompt);
free_array(us->cmds);
us->cmds = nullptr;
exit(RETURN_FAILURE);
return nullptr;
}
free(us->cmds[us->sz]);
us->cmds[us->sz] = nullptr;
return us;
}
static
usr_cmd_t *get_first_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr,
char const *prompt, size_t *bf_len)
{
if (isatty(exec_ctx->read_fd))
printf("%s? ", prompt);
usr->cmds[usr->sz] = nullptr;
getline(&(usr->cmds[usr->sz]), bf_len, stdin);
*bf_len = u_strlen(usr->cmds[usr->sz]);
usr->cmds[usr->sz][*bf_len - 1] = '\0';
usr->sz += 1;
return usr;
}
usr_cmd_t *get_usr_loop_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr_cmd,
char const *prompt)
{
size_t buffer_len;
if (usr_cmd == NULL)
return nullptr;
usr_cmd->cmds = (char **)malloc(sizeof(char *) * usr_cmd->cap);
if ((void *)usr_cmd->cmds == NULL)
return nullptr;
usr_cmd = get_first_cmd(exec_ctx, usr_cmd, prompt, &buffer_len);
while (strcmp("end", usr_cmd->cmds[usr_cmd->sz - 1]) != 0){
if (isatty(exec_ctx->read_fd))
printf("%s? ", prompt);
if (usr_cmd->sz >= usr_cmd->cap)
usr_cmd = buffers_realloc(usr_cmd);
if (usr_cmd == NULL)
return nullptr;
increase_buffers(usr_cmd, &buffer_len);
}
usr_cmd = handle_end(usr_cmd, prompt);
return usr_cmd;
}

View File

@@ -1,25 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** history
*/
#include <stdio.h>
#include "common.h"
#include "exec.h"
int builtins_history(ef_t *ef, char **args __attribute__((unused)))
{
his_command_t *cmd_history = ef->exec_ctx->history_command;
for (int i = 0; i < cmd_history->sz; i++){
if (cmd_history[i].arg) {
printf("%d %s %s\n", i + 1, cmd_history[i].command,
cmd_history[i].arg);
} else
printf("%d %s\n", i + 1, cmd_history[i].command);
}
return RETURN_SUCCESS;
}

View File

@@ -1,165 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "builtins.h"
#include "common.h"
#include "debug.h"
#include "exec.h"
#include "repl.h"
#include "u_str.h"
static
int get_argc(char **args)
{
int i = 0;
for (; args[i] != nullptr; i++);
return i;
}
static
bool ensure_cmds_cap(char ***cmd, size_t sz, size_t *cap)
{
char **tmp;
if (sz + 1 < *cap)
return true;
tmp = (char **)realloc(*cmd, sizeof(char *) * (*cap << 1));
if (!tmp)
return false;
*cap <<= 1;
*cmd = tmp;
return true;
}
static
bool init_block(cmd_block_t *blk)
{
blk->size = 0;
blk->cap = DEFAULT_N_CMD_CAP;
blk->cmds = (char **)malloc(sizeof(char *) * blk->cap);
return blk->cmds != NULL;
}
static
void free_block(cmd_block_t *blk)
{
for (size_t i = 0; i < blk->size; i++)
free(blk->cmds[i]);
free((void *)blk->cmds);
}
static
bool append_block(cmd_block_t *blk, const char *line)
{
if (!ensure_cmds_cap(&blk->cmds, blk->size, &blk->cap))
return false;
blk->cmds[blk->size] = strdup(line);
blk->size++;
return true;
}
static
bool handle_if_buff(if_ctx_t *ctx, cmd_block_t *then_blk,
cmd_block_t *else_blk, bool *in_else)
{
if (strcmp(ctx->buff->str, "else") == 0) {
*in_else = true;
return true;
}
if (strcmp(ctx->buff->str, "endif") == 0)
return false;
if (!*in_else) {
if (!append_block(then_blk, ctx->buff->str))
return false;
} else
if (!append_block(else_blk, ctx->buff->str))
return false;
return true;
}
static
bool read_if_blocks(ef_t *ef, if_ctx_t *ctx, cmd_block_t *then_blk,
cmd_block_t *else_blk)
{
bool in_else = false;
while (true) {
if (isatty(ef->exec_ctx->read_fd))
WRITE_CONST(ctx->ef->out_fd, IF_PROMPT);
if (getline(&ctx->buff->str, &ctx->buff->sz, stdin) == -1)
return false;
ctx->buff->str[strcspn(ctx->buff->str, "\n")] = '\0';
if (strcmp(ctx->buff->str, "else") == 0) {
in_else = true;
continue;
}
if (strcmp(ctx->buff->str, "endif") == 0)
break;
if (!handle_if_buff(ctx, then_blk, else_blk, &in_else))
return false;
}
return true;
}
static
void exec_block(cmd_block_t *blk, ef_t *ef)
{
for (size_t i = 0; i < blk->size; i++)
visitor(blk->cmds[i], ef->exec_ctx);
}
static
bool handle_if_logic(ef_t *ef, bool cond, char *last)
{
if_ctx_t ctx = {.buff = &(buff_t){ .str = nullptr, .sz = 0 }, .ef = ef};
cmd_block_t then_blk;
cmd_block_t else_blk;
if (strcmp("then", last) != 0)
return cond ? visitor(last, ef->exec_ctx), true : true;
if (!init_block(&then_blk) || !init_block(&else_blk))
return false;
if (!read_if_blocks(ef, &ctx, &then_blk, &else_blk))
return false;
if (cond)
exec_block(&then_blk, ef);
else
exec_block(&else_blk, ef);
free_block(&then_blk);
free_block(&else_blk);
free(ctx.buff->str);
return true;
}
int builtins_if(ef_t *ef, char **args)
{
int result;
char *last;
if (args[1] == NULL)
return WRITE_CONST(STDERR_FILENO, "if: Too few arguments.\n"),
RETURN_FAILURE;
if (args[2] == NULL)
return WRITE_CONST(STDERR_FILENO, "if: Empty if.\n"), RETURN_FAILURE;
last = strdup(args[get_argc(args) - 1]);
if (!last)
return RETURN_FAILURE;
args[get_argc(args) - 1] = nullptr;
result = builtins_expr(ef, args);
U_DEBUG("If expr result [%d]\n", result);
if (result == -1)
return free(last), RETURN_FAILURE;
if (!handle_if_logic(ef, result != 0, last))
return free(last), RETURN_FAILURE;
return free(last), RETURN_SUCCESS;
}

View File

@@ -1,123 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** local
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ctx.h"
#include "common.h"
#include "u_mem.h"
#include "u_str.h"
bool check_local_var(char *var, char *func_name)
{
if (!isalpha(var[0]))
return (fprintf(stderr, "%s: Variable name must begin"
" with a letter.\n", func_name), RETURN_FAILURE);
if (!u_str_is_only_alnum(var))
return (fprintf(stderr, "%s: Variable name must contain"
" alphanumeric characters.\n", func_name), RETURN_FAILURE);
return RETURN_SUCCESS;
}
char *get_local_value(local_t *local, char const *key)
{
int key_len = u_strlen(key);
for (size_t i = 0; i < local->sz; i++) {
if (local->local_var[i] == nullptr)
continue;
if (u_strcspn(local->local_var[i], '\t') != key_len)
continue;
if (u_strcmp(local->local_var[i], key) == 0)
return local->local_var[i] + key_len + 1;
}
return nullptr;
}
local_t create_local(void)
{
local_t local = {.sz = 0, .cap = 2};
local.local_var = (char **)malloc(sizeof(char *) * local.cap);
if (local.local_var == nullptr)
return (local_t){.sz = 0, .cap = 2, .local_var = nullptr};
local.local_var[local.sz] = nullptr;
local.sz++;
return local;
}
static
bool ensure_local_capacity(local_t *local)
{
char **new_ptr = nullptr;
if (local->sz < local->cap)
return true;
new_ptr = (char **)u_realloc((void *)local->local_var,
sizeof *local->local_var * local->sz,
sizeof *local->local_var * local->cap << 1);
if (!new_ptr)
return false;
local->cap <<= 1;
local->local_var = new_ptr;
return true;
}
bool set_local(local_t *local, char *var, char *value)
{
char *new_loc = nullptr;
size_t key_len = u_strlen(var);
size_t value_len = u_strlen(value);
if (get_local_value(local, var) != nullptr)
unset_local(local, var);
local->sz++;
if (!ensure_local_capacity(local))
return false;
new_loc = malloc(sizeof(char) * (key_len + value_len + 2));
if (new_loc == nullptr)
return false;
u_bzero(new_loc, key_len + value_len + 2);
u_strcpy(new_loc, var);
new_loc[key_len] = '\t';
if (value_len > 0)
u_strcpy(new_loc + key_len + 1, value);
local->local_var[local->sz - 1] = new_loc;
local->local_var[local->sz] = nullptr;
return true;
}
static
void unset_local_move(local_t *local, size_t i)
{
while (local->local_var[i]) {
local->local_var[i] = local->local_var[i + 1];
i++;
}
}
bool unset_local(local_t *local, char *var)
{
int key_len = u_strlen(var);
for (size_t i = 0; i < local->sz; i++) {
if (local->local_var[i] == nullptr)
continue;
if (u_strcspn(local->local_var[i], '\t') != key_len)
continue;
if (u_strcmp(local->local_var[i], var) == 0) {
unset_local_move(local, i);
local->sz--;
return true;
}
}
return false;
}

View File

@@ -1,174 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** foreach
*/
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.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 "exec.h"
#include "local.h"
#include "loop.h"
#include "u_str.h"
void exit_child(int sig[[gnu::unused]])
{
_exit(sig);
}
static
bool checking_for_error(char **args)
{
if (my_array_len(args) < 3)
return (WRITE_CONST(STDERR_FILENO, "foreach: Too few arguments.\n"),
true);
if (check_local_var(args[1], args[0]))
return true;
return false;
}
static
bool checking_while_error(char **args)
{
if (my_array_len(args) < 2)
return (WRITE_CONST(STDERR_FILENO, "while: Too few arguments.\n"),
true);
if (my_array_len(args) > 2)
return (WRITE_CONST(STDERR_FILENO, "while: Expression Syntax.\n"),
true);
return false;
}
static
int do_a_lap(ef_t *ef, char **args)
{
int status = 0;
for (int i = 0; args[i]; i++)
status = visitor(args[i], ef->exec_ctx);
return status;
}
static
int foreach_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmds)
{
int status = 0;
char **save_cmds = arraydup(usr_cmds->cmds);
if ((void *)save_cmds == nullptr)
exit(84);
for (int i = 2; args[i]; i++){
if (!set_local(ef->exec_ctx->local, args[1], args[i]))
exit(84);
status = do_a_lap(ef, usr_cmds->cmds);
free_array(usr_cmds->cmds);
usr_cmds->cmds = arraydup(save_cmds);
}
free_array(save_cmds);
return status;
}
static
int while_loop(ef_t *ef, usr_cmd_t *usr_cmds, char **args)
{
int status = 0;
char **save_cmds = arraydup(usr_cmds->cmds);
int expr_result;
if ((void *)save_cmds == nullptr)
exit(84);
expr_result = builtins_expr(ef, args);
if (expr_result == -1)
return RETURN_FAILURE;
while (expr_result != 0) {
U_DEBUG("While expr result [%d]\n", expr_result);
status = do_a_lap(ef, usr_cmds->cmds);
free_array(usr_cmds->cmds);
usr_cmds->cmds = arraydup(save_cmds);
expr_result = builtins_expr(ef, args);
if (expr_result == -1)
return RETURN_FAILURE;
}
free_array(save_cmds);
return status;
}
static
int choose_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmd, char const *prompt)
{
if (strcmp(prompt, "foreach") == 0)
return foreach_loop(ef, args, usr_cmd);
return while_loop(ef, usr_cmd, args);
}
static
void launch_loop(ef_t *ef, char **args, char const *prompt)
{
int status = RETURN_FAILURE;
usr_cmd_t *usr_cmds = malloc(sizeof(usr_cmd_t));
ef->exec_ctx->local->in_a_loop = true;
if (usr_cmds == nullptr)
exit(84);
usr_cmds->cap = 2;
usr_cmds->sz = 0;
signal(SIGINT, exit_child);
signal(EOF, exit_child);
usr_cmds = get_usr_loop_cmd(ef->exec_ctx, usr_cmds, prompt);
if (usr_cmds == nullptr)
exit(84);
status = choose_loop(ef, args, usr_cmds, prompt);
free_array(usr_cmds->cmds);
free(usr_cmds);
exit(status);
}
int builtins_foreach(ef_t *ef, char **args)
{
int status = 0;
pid_t pid;
if (checking_for_error(args))
return RETURN_FAILURE;
pid = fork();
if (pid == 0)
launch_loop(ef, args, "foreach");
else
wait(&status);
if (WIFEXITED(status))
ef->history->last_exit_code =
ef->history->last_exit_code ?: WEXITSTATUS(status);
return status;
}
int builtins_while(ef_t *ef, char **args)
{
int status = 0;
pid_t pid;
if (checking_while_error(args))
return RETURN_FAILURE;
pid = fork();
if (pid == 0)
launch_loop(ef, args, "while");
else
wait(&status);
if (WIFEXITED(status))
ef->history->last_exit_code =
ef->history->last_exit_code ?: WEXITSTATUS(status);
return status;
}

View File

@@ -1,55 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** repeat
*/
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "builtins.h"
#include "common.h"
#include "exec.h"
#include "u_str.h"
static
bool checking_error(char **args, long *nb_loop)
{
char *end;
if (my_array_len(args) < 3)
return (WRITE_CONST(STDERR_FILENO, "repeat: Too few arguments.\n"),
true);
*nb_loop = strtol(args[1], &end, 10);
if (end[0] != '\0'){
return (WRITE_CONST(STDERR_FILENO, "repeat: Badly formed number.\n"),
true);
}
return false;
}
int builtins_repeat(ef_t *ef, char **args)
{
long nb_loop = 0;
int status = 0;
pid_t pid;
if (checking_error(args, &nb_loop))
return RETURN_FAILURE;
pid = fork();
if (pid == 0){
signal(SIGINT, exit_child);
for (int i = 0; i < nb_loop; i++)
status = exec_the_args(ef, &args[2]);
exit(status);
} else
wait(&status);
if (WIFEXITED(status))
ef->history->last_exit_code =
ef->history->last_exit_code ?: WEXITSTATUS(status);
return status;
}

View File

@@ -1,73 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** set
*/
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "common.h"
#include "env.h"
#include "exec.h"
#include "u_str.h"
void print_local(ef_t *ef)
{
for (size_t i = 0; i < ef->exec_ctx->local->sz; i++) {
if (ef->exec_ctx->local->local_var[i] == NULL)
continue;
write(ef->out_fd, ef->exec_ctx->local->local_var[i],
u_strlen(ef->exec_ctx->local->local_var[i]));
WRITE_CONST(ef->out_fd, "\n");
}
}
int special_case(ef_t *ef, char **args)
{
int piv = 0;
char *key = NULL;
char *val = NULL;
if (args[1] == NULL)
return print_local(ef), RETURN_SUCCESS;
for (; args[1][piv] && args[1][piv] != '='; piv++);
key = strndup(args[1], piv);
if (key == NULL)
return RETURN_FAILURE;
if (check_local_var(key, args[0]))
return free(key), RETURN_FAILURE;
if (args[1][piv] != '\0')
val = &args[1][piv + 1];
if (!set_local(ef->exec_ctx->local, key, val))
return free(key), RETURN_FAILURE;
free(key);
return RETURN_SUCCESS;
}
int builtins_set(ef_t *ef, char **args)
{
char *var = NULL;
if (my_array_len(args) < 3)
return special_case(ef, args);
for (int i = 1; args[i]; i++){
if (check_local_var(args[i], args[0]))
return RETURN_FAILURE;
var = args[i];
i++;
if (!args[i])
return (set_local(ef->exec_ctx->local, var, NULL)
, RETURN_SUCCESS);
if (strcmp(args[i], "="))
return RETURN_FAILURE;
i++;
if (!set_local(ef->exec_ctx->local, var, args[i]))
return RETURN_FAILURE;
}
return RETURN_SUCCESS;
}

View File

@@ -1,26 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** unset
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "exec.h"
#include "u_str.h"
int builtins_unset(ef_t *ef, char **args)
{
if (args[1] == NULL)
return (WRITE_CONST(STDERR_FILENO, "unset: Too few arguments.\n"),
RETURN_FAILURE);
for (int i = 1; args[i]; i++)
unset_local(ef->exec_ctx->local, args[i]);
return RETURN_SUCCESS;
}

View File

@@ -1,74 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "alias.h"
#include "builtins.h"
#include "common.h"
#include "exec.h"
#include "path.h"
#include "u_str.h"
const char *OTHER_BUILTINS[] = {
"echo"
};
const size_t OTHER_BUILTINS_SZ = sizeof OTHER_BUILTINS
/ sizeof *OTHER_BUILTINS;
static
void search_builtins(ef_t *ef, char *arg)
{
for (size_t i = 0; i < BUILTINS_SZ; i++) {
if (u_strlen(BUILTINS[i].name) != (int)strlen(arg))
continue;
if (u_strcmp(BUILTINS[i].name, arg) == 0)
dprintf(ef->out_fd, "%s is a shell built-in\n", arg);
}
for (size_t i = 0; i < OTHER_BUILTINS_SZ; i++) {
if (u_strlen(OTHER_BUILTINS[i]) != (int)strlen(arg))
continue;
if (u_strcmp(OTHER_BUILTINS[i], arg) == 0)
dprintf(ef->out_fd, "%s is a shell built-in\n", arg);
}
}
static
bool search_cmd(ef_t *ef, char *arg)
{
char *bin_path = parse_full_bin_path(ef->env, arg);
buff_t alias_path = { .str = strdup(arg), strlen(arg) };
if (alias_path.str == NULL)
return false;
if (bin_path == NULL)
return free(alias_path.str), NULL;
parse_alias(&alias_path.str, &alias_path.sz, ef->exec_ctx->alias);
if (strcmp(arg, alias_path.str) != 0)
dprintf(ef->out_fd, "%s is aliased to %s\n", arg, alias_path.str);
search_builtins(ef, arg);
if (strcmp(arg, bin_path) != 0)
dprintf(ef->out_fd, "%s\n", bin_path);
free(alias_path.str);
return true;
}
int builtins_where(ef_t *ef, char **args)
{
if (args[1] == NULL)
return dprintf(STDERR_FILENO, "%s: Too few arguments\n", args[0]),
RETURN_FAILURE;
for (size_t i = 1; args[i] != NULL; i++) {
if (!search_cmd(ef, args[i]))
return RETURN_FAILURE;
}
return RETURN_SUCCESS;
}

View File

@@ -1,80 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "alias.h"
#include "builtins.h"
#include "common.h"
#include "exec.h"
#include "path.h"
#include "u_str.h"
const char *OOTHER_BUILTINS[] = {
"echo"
};
const size_t OOTHER_BUILTINS_SZ = sizeof OOTHER_BUILTINS
/ sizeof *OOTHER_BUILTINS;
static
bool search_builtin(ef_t *ef, char *arg)
{
for (size_t i = 0; i < BUILTINS_SZ; i++) {
if (u_strlen(BUILTINS[i].name) != (int)strlen(arg))
continue;
if (u_strcmp(BUILTINS[i].name, arg) == 0)
return dprintf(ef->out_fd, "%s: shell built-in command.\n", arg),
true;
}
for (size_t i = 0; i < OOTHER_BUILTINS_SZ; i++) {
if (u_strlen(OOTHER_BUILTINS[i]) != (int)strlen(arg))
continue;
if (u_strcmp(OOTHER_BUILTINS[i], arg) == 0)
return dprintf(ef->out_fd, "%s: shell built-in command.\n", arg),
true;
}
return false;
}
static
bool search_cmd(ef_t *ef, char *arg)
{
char *bin_path = parse_full_bin_path(ef->env, arg);
buff_t alias_path = { .str = strdup(arg), strlen(arg) };
if (alias_path.str == NULL)
return false;
if (bin_path == NULL)
return free(alias_path.str), NULL;
parse_alias(&alias_path.str, &alias_path.sz, ef->exec_ctx->alias);
if (strcmp(arg, alias_path.str) != 0)
return dprintf(ef->out_fd, "%s:\t aliased to %s\n", arg,
alias_path.str), true;
if (search_builtin(ef, arg))
return true;
if (strcmp(arg, bin_path) != 0)
return dprintf(ef->out_fd, "%s\n", bin_path), true;
fprintf(stderr, "%s: Command not found.\n", arg);
free(alias_path.str);
return true;
}
int builtins_which(ef_t *ef, char **args)
{
if (args[1] == NULL)
return dprintf(STDERR_FILENO, "%s: Too few arguments\n", args[0]),
RETURN_FAILURE;
for (size_t i = 1; args[i] != NULL; i++) {
if (!search_cmd(ef, args[i]))
return RETURN_FAILURE;
}
return RETURN_SUCCESS;
}

View File

@@ -1,70 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** yes
*/
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include "builtins.h"
#include "common.h"
#include "exec.h"
#include "u_mem.h"
#include "u_str.h"
static
int len_buffer(char **args)
{
int len_buffer = 0;
for (int i = 0; args[i]; i++)
len_buffer += strlen(args[i]) + 1;
return len_buffer;
}
static
char *define_prompt(char **args)
{
char *buffer = nullptr;
if (args[1] == NULL)
return u_strdup("y\n");
buffer = malloc(sizeof(char) * (len_buffer(args) + 1));
if (buffer == NULL)
return nullptr;
u_bzero(buffer, len_buffer(args) + 1);
strcpy(buffer, args[1]);
buffer[strlen(buffer)] = ' ';
for (int i = 2; args[i]; i++){
strcat(buffer, args[i]);
if (args[i + 1] != NULL)
buffer[strlen(buffer)] = ' ';
}
buffer[strlen(buffer)] = '\n';
return buffer;
}
int builtins_yes(ef_t *ef, char **args)
{
char *buffer = define_prompt(args);
pid_t pid;
if (buffer == NULL)
return RETURN_FAILURE;
pid = fork();
if (pid == 0) {
signal(SIGINT, exit_child);
while (true)
write(ef->out_fd, buffer, strlen(buffer));
} else
wait(nullptr);
free(buffer);
return RETURN_SUCCESS;
}

View File

@@ -1,25 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef COMMON_H
#define COMMON_H
#include <stdint.h>
#define PROMPT_HEADER "┌─["
#define IF_PROMPT "if? "
enum {
RETURN_SUCCESS = 0,
RETURN_FAILURE = 1
};
typedef struct {
uint8_t flags;
char *script_file;
char *cmd;
} opt_t;
#endif /* COMMON_H */

View File

@@ -1,47 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef BUILTINS_HANDLER_H
#define BUILTINS_HANDLER_H
#include <termios.h>
#include "alias.h"
#include "env.h"
#include "history.h"
#include "local.h"
#include "shell.h"
typedef struct {
pid_t pgid;
bool running;
bool foreground;
} job_t;
typedef struct {
job_t *jobs;
size_t sz;
size_t cap;
} jobs_t;
typedef struct {
env_t *env;
history_t *history;
his_command_t *history_command;
alias_t *alias;
bool is_running;
struct termios saved_term_settings;
local_t *local;
opt_t *opt;
int read_fd;
int isatty;
jobs_t jobs;
} exec_ctx_t;
size_t update_command(char **buffer,
size_t *buffer_sz, exec_ctx_t *exec_ctx);
#endif /* BUILTINS_HANDLER_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", 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,149 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "env.h"
#include "u_mem.h"
#include "u_str.h"
[[gnu::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]);
}
}
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 nullptr;
}
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] = nullptr;
}
bool set_env(env_t *env, char *key, char *value)
{
char *new_env = nullptr;
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 = nullptr };
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] = nullptr;
U_DEBUG_CALL(debug_env_entries, &new_env);
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,236 +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 "args.h"
#include "ast.h"
#include "builtins.h"
#include "common.h"
#include "debug.h"
#include "env.h"
#include "exec.h"
#include "job.h"
#include "path.h"
#include "repl.h"
#include "u_mem.h"
#include "u_str.h"
const builtins_funcs_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 },
{ "repeat", &builtins_repeat },
{ "exit", &builtins_exit },
{ "history", &builtins_history},
{ "alias", &builtins_alias},
{ "yes", &builtins_yes },
{ "foreach", &builtins_foreach },
{ "while", &builtins_while },
{ "set", &builtins_set },
{ "unset", &builtins_unset },
{ "where", &builtins_where },
{ "which", &builtins_which },
{ "expr", &builtins_expr },
{ "if", &builtins_if },
{ "fg", &builtins_fg },
{ "break", &builtins_break }
};
const size_t BUILTINS_SZ = sizeof BUILTINS / sizeof *BUILTINS;
__attribute__((nonnull))
bool ensure_args_capacity(args_t *args)
{
char **new_ptr;
if (args->sz + 1 < args->cap)
return true;
new_ptr = (char **)u_realloc((void *)args->args, sizeof *args->args *
args->sz, sizeof *args->args * args->cap << 1);
if (!new_ptr)
return false;
args->cap <<= 1;
args->args = new_ptr;
return true;
}
static
char **parse_args(ef_t *ef, ast_t *node)
{
args_t args = { .args = (char **)malloc(sizeof *args.args
* DEFAULT_ARGS_CAP), .sz = 0, .cap = DEFAULT_ARGS_CAP };
if (!args.args)
return nullptr;
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;
if (!process_args(node, &args, &i, ef))
return free((void *)args.args), NULL;
}
if (!ensure_args_capacity(&args))
return nullptr;
args.args[args.sz] = nullptr;
return args.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 exec(char *full_bin_path, char **args, ef_t *ef)
{
execve(full_bin_path, args, ef->env->env);
return command_error(full_bin_path, args, errno);
}
static
int launch_bin(char *full_bin_path, char **args, ef_t *ef)
{
int status;
pid_t pid = fork();
int nohang;
if (pid == 0) {
restore_term_flags(ef->exec_ctx);
set_fd(ef);
init_child_job(ef->exec_ctx, pid);
status = exec(full_bin_path, args, ef);
exit(RETURN_FAILURE);
}
init_child_job(ef->exec_ctx, pid);
nohang = ef->flags & F_PIPE || ef->p_i != ef->p_sz - 1;
waitpid(pid, &status, nohang ? WUNTRACED : WNOHANG);
if (WIFSTOPPED(status)) {
ef->exec_ctx->jobs.jobs[ef->exec_ctx->jobs.sz - 1].running = true;
ef->exec_ctx->jobs.jobs[ef->exec_ctx->jobs.sz - 1].foreground = false;
printf("\n[%lu]+ Continued &\n", ef->exec_ctx->jobs.sz);
}
if (WIFEXITED(status))
ef->exec_ctx->history->last_exit_code =
ef->exec_ctx->history->last_exit_code ?: WEXITSTATUS(status);
tcsetpgrp(ef->exec_ctx->read_fd, ef->exec_ctx->jobs.jobs[0].pgid);
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) {
restore_term_flags(ef->exec_ctx);
ef->exec_ctx->history->last_exit_code =
BUILTINS[i].ptr(ef, args);
return true;
}
}
return false;
}
int exec_the_args(ef_t *ef, char **args)
{
char *full_bin_path;
int status;
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);
return status;
}
int execute(ef_t *ef)
{
char **args;
args = parse_args(ef, ef->act_node);
if (!args)
return RETURN_FAILURE;
exec_the_args(ef, args);
free((void *)args);
init_shell_repl(ef->exec_ctx);
return ef->exec_ctx->history->last_exit_code
!= 0 ? RETURN_FAILURE : RETURN_SUCCESS;
}

View File

@@ -1,60 +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 sz;
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;
exec_ctx_t *exec_ctx;
} ef_t;
__attribute__((nonnull))
int execute(ef_t *ef);
bool ensure_args_capacity(args_t *args);
int exec_the_args(ef_t *ef, char **args);
void exit_child(int sig __attribute__((unused)));
int visit_loop(ef_t *ef, ast_t *node);
void handle_var_case(ast_t *node, exec_ctx_t *ctx, size_t *i, args_t *args);
bool handle_magic_quotes(ast_t *node, exec_ctx_t *ctx,
size_t *i, args_t *args);
bool handle_var(ast_t *node, size_t *i, exec_ctx_t *ctx, args_t *args);
char *get_values(exec_ctx_t *ctx, char *key);
#endif /* EXEC_H */

View File

@@ -1,107 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** handle_quotes
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include "ast.h"
#include "env.h"
#include "local.h"
#include "exec.h"
#include "u_str.h"
static
char *set_f_part(char *node_str)
{
char *f_part = strdup(node_str);
int i = 0;
if (f_part == NULL)
return NULL;
for (; f_part[i] && f_part[i] != '$'; i++);
f_part[i] = '\0';
return f_part;
}
static
char *set_s_part(char *node_str, int len_f_part, ast_t *node, size_t *i)
{
int pointer_rank = len_f_part;
for (; pointer_rank < node->vector.tokens[*i].sz && node_str[pointer_rank]
&& !isblank(node_str[pointer_rank]); pointer_rank++);
return strndup(&node_str[pointer_rank],
node->vector.tokens[*i].sz - pointer_rank);
}
static
bool concat_and_free(char *var, char *f_part, char *s_part, args_t *args)
{
args->args[args->sz] = malloc(sizeof(char) *
(strlen(f_part) + strlen(s_part) + strlen(var) + 1));
if (args->args[args->sz] == NULL)
return free(f_part), true;
strcpy(args->args[args->sz], f_part);
strcat(args->args[args->sz], var);
strcat(args->args[args->sz], s_part);
free(s_part);
free(f_part);
return false;
}
static
bool concat_var(char *var, args_t *args, ast_t *node, size_t *i)
{
char *f_part = set_f_part(node->vector.tokens[*i].str);
char *s_part = NULL;
args->args[args->sz] = var;
if (f_part == NULL)
return true;
s_part = set_s_part(node->vector.tokens[*i].str, strlen(f_part), node, i);
if (s_part == NULL)
return free(f_part), true;
return concat_and_free(var, f_part, s_part, args);
}
char *get_key(ast_t *node, size_t *i)
{
size_t id = 0;
for (; node->vector.tokens[*i].str &&
id < node->vector.tokens[*i].sz; id++)
if (node->vector.tokens[*i].str[id] == '$'){
id++;
return strndup(&node->vector.tokens[*i].str[id],
node->vector.tokens[*i].sz - id);
}
return NULL;
}
bool handle_var(ast_t *node, size_t *i, exec_ctx_t *ctx, args_t *args)
{
char *key = get_key(node, i);
char *var = NULL;
int end_key = 0;
if (key == NULL){
args->args[args->sz] = strndup(node->vector.tokens[*i].str,
node->vector.tokens[*i].sz);
return false;
}
if (key == NULL)
return true;
for (; key[end_key] && !isblank(key[end_key]); end_key++);
key[end_key] = '\0';
var = get_values(ctx, key);
free(key);
if (var == NULL)
return true;
return concat_var(var, args, node, i);
}

View File

@@ -1,147 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** handle_vars
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include "ast.h"
#include "env.h"
#include "local.h"
#include "exec.h"
char *get_values(exec_ctx_t *ctx, char *key)
{
char *r_char = NULL;
r_char = get_env_value(ctx->env, key);
if (r_char == NULL)
r_char = get_local_value(ctx->local, key);
if (r_char == NULL) {
fprintf(stderr, "%s: Undefined variable.\n", key);
return NULL;
}
return r_char;
}
static
char *take_next_parenthese_arg(ast_t *node, size_t *in_str, size_t *i)
{
size_t end = 0;
char *buff;
while (node->vector.tokens[*i].sz > *in_str &&
isblank(node->vector.tokens[*i].str[*in_str]))
*in_str = *in_str + 1;
for (; node->vector.tokens[*i].sz > *in_str + end &&
!isblank(node->vector.tokens[*i].str[*in_str + end]); end++);
buff = strndup(&node->vector.tokens[*i].str[*in_str], end);
*in_str += end;
return buff;
}
static
bool handle_parentheses(ast_t *node, exec_ctx_t *ctx, size_t *i, args_t *args)
{
size_t in_str = 0;
char *vl;
while (in_str < node->vector.tokens[*i].sz){
if (!ensure_args_capacity(args))
return false;
vl = take_next_parenthese_arg(node, &in_str, i);
if (vl == NULL)
return free((void *)args->args), false;
args->args[args->sz] = vl;
args->sz++;
}
args->args[args->sz] = NULL;
args->sz--;
return true;
}
static
bool check_parentheses(ast_t *node, size_t *i, exec_ctx_t *ctx, args_t *args)
{
if (!strchr("()", node->vector.tokens[*i].str[0]))
return true;
if (strlen(node->vector.tokens[*i].str) == 1 ||
(node->vector.tokens[*i].str[0] == '(' &&
node->vector.tokens[*i].str[node->vector.tokens[*i].sz - 1] != ')'))
return (fprintf(stderr, "Too many ('s.\n"), true);
if (node->vector.tokens[*i].str[0] == ')')
return (fprintf(stderr, "Too many )'s.\n"), true);
node->vector.tokens[*i].str[node->vector.tokens[*i].sz - 1] = '\0';
node->vector.tokens[*i].str = &node->vector.tokens[*i].str[1];
node->vector.tokens[*i].sz -= 2;
if (!handle_parentheses(node, ctx, i, args))
return true;
return false;
}
static
bool format_quotes(ast_t *node, char be_matched, size_t *i)
{
char *last_quote = strchr(node->vector.tokens[*i].str, be_matched);
if (last_quote == NULL)
return (fprintf(stderr, "Unmatched \'%c\'.\n", be_matched), false);
node->vector.sz -= 2;
if (isblank(last_quote[1] || be_matched == '`')){
last_quote[0] = '\0';
return true;
} else
node->vector.tokens[*i].str[node->vector.tokens[*i].sz - 1] = '\0';
memmove(&last_quote[0], &last_quote[1], strlen(last_quote));
last_quote = strchr(node->vector.tokens[*i].str, be_matched);
if (strchr(node->vector.tokens[*i].str, be_matched))
return (fprintf(stderr, "Unmatched \'%c\'.\n", be_matched), false);
node->vector.tokens[*i].str[node->vector.tokens[*i].sz - 2] = '\0';
return true;
}
static
bool check_quotes(ast_t *node, size_t *i, exec_ctx_t *ctx, args_t *args)
{
char be_matched = node->vector.tokens[*i].str[0];
if (!strchr("\'\"`", node->vector.tokens[*i].str[0]))
return true;
if (node->vector.tokens[*i].sz == 1)
return (fprintf(stderr, "Unmatched \'%c\'.\n", be_matched), true);
memmove(&node->vector.tokens[*i].str[0],
&node->vector.tokens[*i].str[1], node->vector.tokens[*i].sz);
if (!format_quotes(node, be_matched, i))
return true;
if (be_matched == '`')
return handle_magic_quotes(node, ctx, i, args);
if (be_matched == '\"')
return handle_var(node, i, ctx, args);
args->args[args->sz] = strdup(node->vector.tokens[*i].str);
return false;
}
bool check_for_closable(ast_t *node, exec_ctx_t *ctx, size_t *i, args_t *args)
{
if (!strchr("\'\"`()", node->vector.tokens[*i].str[0]))
return false;
if (!check_parentheses(node, i, ctx, args))
return true;
else if (!check_quotes(node, i, ctx, args))
return true;
args->args[args->sz] = NULL;
return true;
}
void handle_var_case(ast_t *node, exec_ctx_t *ctx, size_t *i, args_t *args)
{
if (check_for_closable(node, ctx, i, args))
return;
handle_var(node, i, ctx, args);
}

View File

@@ -1,54 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef HISTORY_H
#define HISTORY_H
#define CHAR_HIST '!'
#define TWO_CHAR_CMD 3
#include <stddef.h>
typedef struct history_variable_s {
int coord_variable;
int size_variable;
int type;
char *str;
int id;
} his_variable_t;
typedef struct history_command_s {
int id;
char *command;
char *arg;
int sz;
} his_command_t;
typedef struct parsing_history_s {
char const *name;
char *(*funct)(char *, his_variable_t *, his_command_t *);
} parsing_history_t;
extern const parsing_history_t tab_fnct[];
int parse_history(char **pointer_line,
size_t *buffer_len, size_t *buffer_sz, his_command_t **cmd_history);
char *his_last_command(char *line,
his_variable_t *his_variable, his_command_t *his_command);
char *his_last_same_command(char *line,
his_variable_t *his_variable, his_command_t *his_command);
char *his_id_command(char *line,
his_variable_t *his_variable, his_command_t *his_command);
char *his_last_word(char *line,
his_variable_t *his_variable, his_command_t *his_command);
char *his_last_arg(char *line,
his_variable_t *his_variable, his_command_t *his_command);
his_command_t *fill_cmd_history(his_command_t *cmd_history);
int save_cmd_history(his_command_t *cmd_history);
his_command_t set_cmd(char *line, his_command_t cmd_struct);
#endif /* HISTORY_H */

View File

@@ -1,46 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** init_history
*/
#include <fcntl.h>
#include <unistd.h>
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "history.h"
#include "ctype.h"
static char *get_arg(char *line, int x, int end_cmd)
{
char *tmp = malloc(sizeof(char) * ((x - end_cmd) + 1));
if (tmp != NULL) {
tmp = strncpy(tmp, &line[end_cmd], x - end_cmd);
tmp[x - end_cmd] = '\0';
}
return tmp;
}
his_command_t set_cmd(char *line, his_command_t cmd_struct)
{
int x = 0;
int end_cmd;
while (line[x] != '\0' && !isblank(line[x]))
x++;
cmd_struct.command = malloc((sizeof(char) * x + 1));
if (cmd_struct.command != NULL) {
cmd_struct.command = strncpy(cmd_struct.command, line, x);
cmd_struct.command[x] = '\0';
}
end_cmd = x + 1;
while (line[x] != '\0')
x++;
if (x <= end_cmd)
return cmd_struct;
cmd_struct.arg = get_arg(line, x, end_cmd);
return cmd_struct;
}

View File

@@ -1,82 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdlib.h>
#include <unistd.h>
#include "debug.h"
#include "ctx.h"
#include "job.h"
static
void set_ignored_signals(int child)
{
signal(SIGTTOU, child ? SIG_DFL : SIG_IGN);
signal(SIGTTIN, child ? SIG_DFL : SIG_IGN);
}
bool ensure_jobs_capacity(jobs_t *jobs)
{
job_t *tmp;
if (jobs->sz + 1 < jobs->cap)
return true;
tmp = realloc(jobs->jobs, sizeof *jobs->jobs * jobs->cap << 1);
if (tmp == nullptr)
return false;
jobs->jobs = tmp;
jobs->cap <<= 1;
return true;
}
bool set_child_fg(exec_ctx_t *ec, size_t idx)
{
if (tcsetpgrp(ec->read_fd, ec->jobs.jobs[idx].pgid) < 0)
return false;
kill(-ec->jobs.jobs[idx].pgid, SIGCONT);
return true;
}
bool init_child_job(exec_ctx_t *ec, pid_t pid)
{
if (pid == 0) {
setpgid(0, 0);
if (tcsetpgrp(ec->read_fd, getpid()) < 0)
return false;
set_ignored_signals(1);
} else {
setpgid(pid, pid);
if (!ensure_jobs_capacity(&ec->jobs))
return false;
ec->jobs.jobs[ec->jobs.sz].pgid = pid;
ec->jobs.jobs[ec->jobs.sz].running = true;
ec->jobs.jobs[ec->jobs.sz].foreground = true;
ec->jobs.sz++;
if (tcsetpgrp(ec->read_fd, pid) < 0)
return false;
}
return true;
}
bool init_jobs(exec_ctx_t *ec)
{
if (ec->read_fd != STDIN_FILENO || !isatty(ec->read_fd))
return true;
ec->jobs.cap = DEFAULT_JOBS_CAP;
ec->jobs.jobs = malloc(sizeof *ec->jobs.jobs * ec->jobs.cap);
if (ec->jobs.jobs == nullptr)
return false;
ec->jobs.jobs[0].pgid = getpid();
ec->jobs.jobs[0].running = true;
ec->jobs.sz = 1;
if (setpgid(ec->jobs.jobs[0].pgid, ec->jobs.jobs[0].pgid) < 0)
return false;
if (tcsetpgrp(STDIN_FILENO, ec->jobs.jobs[0].pgid) < 0)
return false;
set_ignored_signals(0);
return true;
}

View File

@@ -1,19 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef JOB_H
#define JOB_H
#include <sys/wait.h>
#include "ctx.h"
#define DEFAULT_JOBS_CAP 4
bool ensure_jobs_capacity(jobs_t *jobs);
bool init_jobs(exec_ctx_t *ec);
bool init_child_job(exec_ctx_t *ec, pid_t pid);
bool set_child_fg(exec_ctx_t *ec, size_t idx);
#endif /* JOB_H */

View File

@@ -1,25 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef LOCAL_H
#define LOCAL_H
#include <stdbool.h>
#include <stddef.h>
typedef struct {
size_t sz;
size_t cap;
char **local_var;
bool in_a_loop;
} local_t;
bool set_local(local_t *local, char *var, char *value);
bool check_local_var(char *var, char *func_name);
bool unset_local(local_t *local, char *var);
char *get_local_value(local_t *local, char const *key);
local_t create_local(void);
#endif /* LOCAL_H */

View File

@@ -1,23 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef LOOP_H
#define LOOP_H
#include <stdbool.h>
#include <stddef.h>
#include "exec.h"
typedef struct {
size_t sz;
size_t cap;
char **cmds;
} usr_cmd_t;
usr_cmd_t *get_usr_loop_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr_cmd,
char const *prompt);
#endif /* LOOP_H */

View File

@@ -1,121 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** magic_quotes
*/
#include <glob.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "exec.h"
#include "u_mem.h"
static
void exec_magic(ast_t *node, exec_ctx_t *ctx, size_t *i, int fd[2])
{
pid_t pid = 0;
node->vector.tokens[*i].str[node->vector.tokens[*i].sz - 1] = '\0';
pid = fork();
if (pid == 0){
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
visitor(node->vector.tokens[*i].str, ctx);
close(fd[1]);
exit(ctx->history->last_exit_code);
}
wait(&ctx->history->last_exit_code);
}
char *realloc_buffer(char *to_return, size_t *sz, size_t *i)
{
char *temp;
if (to_return == NULL){
*sz = 2;
*i = 0;
to_return = malloc(sizeof(char) * *sz);
}
if (*i >= *sz){
temp = realloc(to_return, *sz << 1);
*sz = *sz << 1;
if (temp == NULL)
return free(to_return), NULL;
to_return = temp;
}
return to_return;
}
char *add_to_args(char *to_return, args_t *args, size_t *sz, size_t i)
{
to_return = realloc_buffer(to_return, sz, &i);
if (to_return == NULL)
return NULL;
to_return[i] = '\0';
if (!ensure_args_capacity(args))
return (free(to_return), NULL);
args->args[args->sz] = to_return;
args->sz++;
return NULL;
}
char *handle_buffer(char *to_return, size_t *sz, size_t *i, char buf)
{
to_return = realloc_buffer(to_return, sz, i);
if (to_return == NULL)
return NULL;
to_return[*i] = buf;
return to_return;
}
static
void put_output(int fd[2], args_t *args, char *to_return, size_t sz)
{
char buf;
for (size_t i = 0; read(fd[0], &buf, 1) > 0; i++){
if (strchr("$'", buf)){
i--;
continue;
}
if (buf == '\n'){
to_return = add_to_args(to_return, args, &sz, i);
continue;
}
to_return = handle_buffer(to_return, &sz, &i, buf);
}
args->sz--;
}
static
void get_output(int fd[2], args_t *args)
{
size_t sz = 2;
char *to_return = malloc(sizeof(char) * sz);
if (to_return == NULL)
return;
put_output(fd, args, to_return, sz);
}
bool handle_magic_quotes(ast_t *node, exec_ctx_t *ctx,
size_t *i, args_t *args)
{
int fd[2];
if (pipe(fd) == -1)
return true;
exec_magic(node, ctx, i, fd);
close(fd[1]);
get_output(fd, args);
close(fd[0]);
return false;
}

View File

@@ -1,57 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "debug.h"
#include "shell.h"
const char OPT_FLAGS[] = "hc:";
static
void print_usages(FILE *file, char *bin)
{
fprintf(file, "Usage: %s [-c command] [-dixv]"
" [file]\n", bin);
}
static
bool parse_args(opt_t *opt, int ac, char **av)
{
for (int o = getopt(ac, av, OPT_FLAGS); o != -1;
o = getopt(ac, av, OPT_FLAGS)) {
switch (o) {
case 'h':
exit((print_usages(stdout, av[0]), RETURN_SUCCESS));
case 'c':
opt->cmd = strdup(optarg);
break;
default:
return print_usages(stderr, av[0]), false;
}
}
if (optind < ac) {
opt->script_file = av[optind];
U_DEBUG("Script file [%s]\n", opt->script_file);
} else {
U_DEBUG_MSG("No script file provided.\n");
}
return true;
}
int main(int ac, char **av, char **env)
{
opt_t opt = { 0, .script_file = nullptr, .cmd = nullptr };
U_DEBUG_MSG("Debug mode altivated.\n");
if (!parse_args(&opt, ac, av))
return RETURN_FAILURE;
return shell(&opt, env);
}

View File

@@ -1,129 +0,0 @@
/*
** EPITECH PROJECT, 2025
** history_42sh
** File description:
** his for history
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "history.h"
#include "u_str.h"
#include "utils.h"
const parsing_history_t tab_fnct[] = {
{"!!", &his_last_command},
{"!$", &his_last_word},
{"!*", &his_last_arg},
{"![command]", &his_last_same_command},
{"![number]", &his_id_command},
};
static
int cmd_history_is_in(char *line)
{
for (int i = 0; line[i] != 0; i++)
if (line[i] == CHAR_HIST &&
(line[i + 1] != ' ' && line[i + 1] != '\t'
&& line[i + 1] != '\0'))
return 0;
return 1;
}
static
int is_two_char_cmd(char *line, int coord_x)
{
if (line[coord_x] != CHAR_HIST)
return -1;
coord_x++;
switch (line[coord_x]){
case '!':
return 0;
case '$':
return 1;
case '*':
return 2;
default:
return -1;
}
}
static
int choose_id_or_last(his_variable_t *his_variable, int index_str, char *str)
{
int mode = 0;
const int cpy_index = index_str;
if (str[index_str] != CHAR_HIST && is_a_token(str, index_str + 1) == false)
return -1;
index_str++;
for (; str[index_str] != 0; index_str++){
if (is_a_token(str, index_str) == true || isblank(str[index_str]))
break;
if (!isdigit(str[index_str]))
mode = 1;
}
his_variable->coord_variable = cpy_index;
his_variable->size_variable = index_str - cpy_index;
his_variable->str = strn_to_ndup(cpy_index, (index_str - cpy_index), str);
if (his_variable->str == NULL)
return 3;
his_variable->id = atoi(his_variable->str + 1);
free(his_variable->str);
return (mode == 1) ? 3 : 4;
}
static
int which_his_cmd(his_variable_t *his_variable, char const *line)
{
for (int i = 0; line[i] != '\0'; i++){
his_variable->type = is_two_char_cmd(line, i);
if (his_variable->type != -1){
his_variable->coord_variable = i;
his_variable->size_variable = 2;
return 0;
}
his_variable->type = choose_id_or_last(his_variable, i, line);
if (his_variable->type != -1)
return 0;
}
return 0;
}
static
char *replace_history(char *line, his_command_t *cmd_history)
{
his_variable_t his_variable = {.coord_variable = 0,
.id = 0, .size_variable = 0, .str = NULL, .type = -1};
which_his_cmd(&his_variable, line);
while (his_variable.type != -1){
line = tab_fnct[his_variable.type].funct(line, &his_variable,
cmd_history);
if (line == NULL)
return NULL;
which_his_cmd(&his_variable, line);
}
return line;
}
int parse_history(char **pointer_line,
size_t *buffer_len, size_t *buffer_sz, his_command_t **cmd_history)
{
char *line = *pointer_line;
*buffer_sz = 0;
if (cmd_history_is_in(line) == 0){
line = replace_history(line, *cmd_history);
if (line == NULL)
return 84;
*buffer_len = u_strlen(line) + 1;
*pointer_line = line;
return 0;
}
return 0;
}

View File

@@ -1,68 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.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 nullptr;
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 = nullptr;
char *token;
char *full_path;
if (path_env) {
*dup_path = u_strdup(path_env);
if (!*dup_path)
return nullptr;
token = strtok_r(*dup_path, ":", &saveptr);
} else
token = strtok_r(nullptr, ":", &saveptr);
if (!token)
return u_strdup(binary);
full_path = build_full_path(token, binary);
if (!full_path)
return nullptr;
return access(full_path, X_OK) == 0 ? full_path : (free(full_path),
find_binary(nullptr, 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 = nullptr;
char *full_bin_path;
if (path == nullptr)
path = DEFAULT_PATH;
full_bin_path = find_binary(path, bin_name, &dup_path);
if (full_bin_path == nullptr)
return nullptr;
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,119 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <ctype.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "common.h"
#include "readline.h"
#include "debug.h"
#include "repl.h"
#include "u_str.h"
static
bool str_printable(char const *str, size_t size)
{
for (size_t i = 0; i < size; i++)
if (!isprint(str[i]))
return false;
return true;
}
static
bool ensure_buff_av_capacity(buff_t *buff, size_t requested)
{
char *new_str;
size_t endsize = BUFF_INIT_SZ;
if ((buff->sz + requested) < buff->cap)
return true;
for (; endsize < buff->sz + requested; endsize <<= 1);
if (endsize > buff->cap) {
new_str = realloc(buff->str, (sizeof *buff->str) * endsize);
if (new_str == NULL)
return false;
buff->str = new_str;
buff->cap = endsize;
}
return true;
}
static
bool ensure_buff_capacity(buff_t *buff)
{
char *new_str;
if (buff->str == NULL) {
new_str = malloc((sizeof *buff->str) * BUFF_INIT_SZ);
if (new_str == NULL)
return false;
buff->str = new_str;
buff->cap = BUFF_INIT_SZ;
}
if (buff->sz == buff->cap) {
new_str = realloc(buff->str, (sizeof *buff->str) * buff->cap << 1);
if (new_str == NULL)
return false;
buff->str = new_str;
buff->cap <<= 1;
}
return true;
}
static
bool append_null_terminator(buff_t *buff, exec_ctx_t *exec_ctx)
{
if (!ensure_buff_av_capacity(buff, 1))
return false;
buff->str[buff->sz - 1] = '\0';
buff->sz++;
if (isatty(exec_ctx->read_fd))
WRITE_CONST(STDOUT_FILENO, "\n");
return true;
}
static
int8_t handle_line_buff(exec_ctx_t *exec_ctx, buff_t *buff, char *read_buff,
ssize_t read_size)
{
if (handle_keys(exec_ctx, buff, read_buff))
return RETURN_SUCCESS;
if (isatty(exec_ctx->read_fd) && str_printable(read_buff, read_size))
write(STDOUT_FILENO, read_buff, read_size);
if (!ensure_buff_av_capacity(buff, read_size))
return RETURN_FAILURE;
strncpy(buff->str + buff->sz,
read_buff, read_size);
buff->sz += read_size;
return -1;
}
bool readline(exec_ctx_t *exec_ctx, buff_t *buff, int fd)
{
char read_buff[2] = "";
ssize_t read_size = 0;
if (!ensure_buff_capacity(buff))
return false;
while (strchr(read_buff, '\n') == NULL && *read_buff != '\r') {
memset(read_buff, '\0', sizeof read_buff);
read_size = read(fd, &read_buff, sizeof read_buff - 1);
if (read_size < 0)
return false;
if (read_size == 0)
return true;
if (handle_line_buff(exec_ctx, buff, read_buff, read_size) > -1)
return true;
}
return append_null_terminator(buff, exec_ctx);
}

View File

@@ -1,17 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef READLINE
#define READLINE
#define BUFF_INIT_SZ 16
#include <stdbool.h>
#include "exec.h"
#include "u_str.h"
bool readline(exec_ctx_t *exec_ctx, buff_t *buff, int fd);
#endif /* READLINE */

View File

@@ -1,91 +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"
#include "debug.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;
U_DEBUG("Redirect sz [%lu] i [%lu]\n", sz, i);
if (i + 1 >= 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 + 1 >= 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 + 1 >= 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,81 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <signal.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include "common.h"
#include "exec.h"
#include "repl.h"
#include "u_str.h"
#include "vt100_esc_codes.h"
void print_shell_prompt(exec_ctx_t *exec_ctx)
{
env_t *env_ptr = exec_ctx->env;
char const *ps1 = get_env_value(env_ptr, "PS1");
char hostname[64];
if (ps1 == nullptr) {
if (gethostname(hostname, 64) < 0)
return;
printf(BLUE PROMPT_HEADER GREEN "%s" RESET "@" CYAN "%s" BLUE "] "
RESET "-" BLUE " [" RESET "%s" BLUE
"] " RESET "-" BLUE " [" YELLOW "%d" BLUE
"]\n└─[" PURPLE "$" BLUE "] " RESET,
get_env_value(env_ptr, "USER"),
hostname,
get_env_value(env_ptr, "PWD"),
exec_ctx->history_command->sz);
} else
printf("%s", ps1);
}
void init_shell_repl(exec_ctx_t *exec_ctx)
{
struct termios repl_settings;
tcgetattr(STDIN_FILENO, &repl_settings);
exec_ctx->saved_term_settings = repl_settings;
exec_ctx->is_running = true;
if (isatty(exec_ctx->read_fd)) {
setvbuf(stdout, nullptr, _IONBF, 0);
signal(SIGINT, SIG_IGN);
WRITE_CONST(STDOUT_FILENO, BLINKING_VERTICAL_CURSOR);
repl_settings.c_iflag = IXON;
repl_settings.c_lflag = ~(ECHO | ICANON);
tcsetattr(STDIN_FILENO, TCSANOW, &repl_settings);
}
}
void restore_term_flags(exec_ctx_t *exec_ctx)
{
tcsetattr(STDIN_FILENO, TCSANOW, &exec_ctx->saved_term_settings);
}
void ignore_sigint(exec_ctx_t *exec_ctx)
{
WRITE_CONST(STDIN_FILENO, "\n");
print_shell_prompt(exec_ctx);
}
bool handle_keys(exec_ctx_t *exec_ctx, buff_t *buff, char const *read_buff)
{
switch (*read_buff) {
case CTRL('d'):
buff->sz = 0;
return true;
case CTRL('c'):
ignore_sigint(exec_ctx);
return false;
default:
return false;
}
}

View File

@@ -1,18 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef REPL_H
#define REPL_H
#include "exec.h"
#include "u_str.h"
void init_shell_repl(exec_ctx_t *exec_ctx);
void restore_term_flags(exec_ctx_t *exec_ctx);
bool handle_keys(exec_ctx_t *exec_ctx, buff_t *buff, char const *read_buff);
void print_shell_prompt(exec_ctx_t *exec_ctx);
void ignore_sigint(exec_ctx_t *exec_ctx);
#endif /* REPL_H */

View File

@@ -1,151 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include "ctx.h"
#include "debug.h"
#include "env.h"
#include "history.h"
#include "job.h"
#include "local.h"
#include "readline.h"
#include "repl.h"
#include "shell.h"
#include "u_str.h"
#include "utils.h"
static
void check_basic_error(char const *buffer)
{
if (buffer == NULL)
return;
if (*buffer == '|')
WRITE_CONST(STDERR_FILENO, "Invalid null command.\n");
if (*buffer == '>' || *buffer == '<')
WRITE_CONST(STDERR_FILENO, "Missing name for redirect.\n");
}
static
void write_prompt(int is_a_tty, exec_ctx_t *exec_ctx)
{
if (is_a_tty)
print_shell_prompt(exec_ctx);
}
static
bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx)
{
char *tmp_buff = nullptr;
size_t buffer_len;
buff->sz = 0;
if (!readline(exec_ctx, buff, exec_ctx->read_fd))
return false;
if (!buff->sz)
return false;
tmp_buff = buff->str;
buffer_len = update_command(&tmp_buff, &buff->sz, exec_ctx);
if (buffer_len == 0)
return true;
if (buffer_len < 1 || !u_str_is_alnum(tmp_buff))
return check_basic_error(tmp_buff), true;
U_DEBUG("Buffer [%lu] [%s]\n", buffer_len, tmp_buff);
if (visitor(tmp_buff, exec_ctx) == RETURN_FAILURE
&& !exec_ctx->history->last_exit_code)
exec_ctx->history->last_exit_code = RETURN_FAILURE;
return true;
}
static
int shell_loop(int is_a_tty, exec_ctx_t *exec_ctx)
{
buff_t buff = { .str = nullptr, 0, .cap = BUFF_INIT_SZ };
init_shell_repl(exec_ctx);
if (exec_ctx->opt->cmd != nullptr)
return visitor(exec_ctx->opt->cmd, exec_ctx);
while (true) {
write_prompt(is_a_tty, exec_ctx);
if (!change_shell_command(&buff, exec_ctx))
return exec_ctx->history->last_exit_code;
}
return free(buff.str), exec_ctx->history->last_exit_code;
}
static
his_command_t *init_cmd_history(void)
{
his_command_t *cmd_history = malloc(sizeof(his_command_t) * 100);
if (cmd_history == NULL)
return nullptr;
for (int i = 0; i < 100; i++){
cmd_history[i].arg = nullptr;
cmd_history[i].command = nullptr;
cmd_history[i].id = i;
}
cmd_history->sz = 0;
return cmd_history;
}
static
bool error_in_init(exec_ctx_t *exec_ctx)
{
if (!exec_ctx->history_command || !exec_ctx->env->env
|| !exec_ctx->alias->alias_array ||
!exec_ctx->alias->alias_to_replace) {
free(exec_ctx->alias->alias_array);
free(exec_ctx->alias->alias_to_replace);
free(exec_ctx->history_command);
free(exec_ctx->env->env);
return true;
}
return false;
}
static
int get_read_fd(opt_t *opt)
{
int fd;
if (opt->script_file == NULL)
return STDIN_FILENO;
fd = open(opt->script_file, O_RDONLY);
if (fd < 0)
return perror(opt->script_file), -1;
return fd;
}
int shell(opt_t *opt, char **env_ptr)
{
alias_t alias = init_alias();
env_t env = parse_env(env_ptr);
history_t history = { .cmd_history = nullptr, .last_exit_code = 0,
.last_chdir = nullptr};
his_command_t *cmd_history = init_cmd_history();
local_t local = create_local();
exec_ctx_t exec_ctx = {.env = &env, .local = &local, .opt = opt,
.read_fd = get_read_fd(opt), .history = &history,
.history_command = cmd_history, .alias = &alias};
int shell_result;
if (exec_ctx.read_fd == -1 || (int)error_in_init(&exec_ctx)
|| !(int)init_jobs(&exec_ctx))
return RETURN_FAILURE;
shell_result = shell_loop(isatty(exec_ctx.read_fd), &exec_ctx);
if (opt->cmd == NULL && isatty(exec_ctx.read_fd)) {
WRITE_CONST(STDOUT_FILENO, "exit\n");
restore_term_flags(&exec_ctx);
}
return free_everything(&exec_ctx), shell_result;
}

View File

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

View File

@@ -1,53 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** update_command
*/
#include "common.h"
#include "ctx.h"
#include "history.h"
#include "u_str.h"
static
int check_cmd(char *cmd)
{
if (!cmd)
return 84;
for (int i = 0; cmd[i] != 0; i++)
if (cmd[i] == CHAR_HIST &&
(cmd[i + 1] != ' ' && cmd[i + 1] != '\t'
&& cmd[i + 1] != '\0'))
return 84;
return 0;
}
his_command_t *save_command(char *cmd, his_command_t *cmd_history)
{
if (check_cmd(cmd) == 84)
return cmd_history;
if (cmd_history->sz < 100) {
cmd_history[cmd_history->sz] = set_cmd(cmd,
cmd_history[cmd_history->sz]);
}
cmd_history->sz++;
return cmd_history;
}
size_t update_command(char **buffer,
size_t *buffer_sz, exec_ctx_t *exec_ctx)
{
size_t buffer_len = 0;
buffer_len = u_strlen(*buffer);
if (buffer_len < 2)
return RETURN_FAILURE;
if (parse_history(buffer, &buffer_len,
buffer_sz, &exec_ctx->history_command) == 84)
return RETURN_SUCCESS;
parse_alias(buffer, &buffer_len, exec_ctx->alias);
exec_ctx->history_command = save_command(*buffer,
exec_ctx->history_command);
return buffer_len;
}

View File

@@ -1,20 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef UTILS_H
#define UTILS_H
#include "history.h"
#include "exec.h"
char *strn_to_ndup(int start, int size, char *str);
bool is_a_token(char *str, int index_str);
char *cat_in_str(his_variable_t *his_variable, char *str, char *cpy);
int len_array(char **array);
char *insert_str(const char *base, const char *insert, size_t pos);
void free_everything(exec_ctx_t *exec_ctx);
#endif /* UTILS_H */

View File

@@ -1,43 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** cat_in_str
*/
#include "history.h"
#include <string.h>
#include <stdlib.h>
static
int insert_in_str(char *dest, char *cpy, int start)
{
for (int j = 0; cpy[j] != '\0'; j++){
dest[start] = cpy[j];
start++;
}
return start;
}
char *cat_in_str(his_variable_t *his_variable, char *str, char *cpy)
{
int i = 0;
int len_str = strlen(str);
int size_right = len_str -
his_variable->coord_variable - his_variable->size_variable;
int size_left = (len_str - size_right) - his_variable->size_variable;
char *new_str = malloc(sizeof(char) *
(size_right + size_left + strlen(cpy) + 2));
if (new_str == NULL)
return NULL;
for (; i < size_left; i++)
new_str[i] = str[i];
i = insert_in_str(new_str, cpy, i);
for (int k = 0; k < size_right; k++){
new_str[i] = str[k + size_left + his_variable->size_variable];
i++;
}
new_str[i] = '\0';
new_str[i + 1] = '\0';
return new_str;
}

View File

@@ -1,17 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdlib.h>
#include "exec.h"
void free_everything(exec_ctx_t *exec_ctx)
{
free_env(exec_ctx->env);
free_alias(exec_ctx->alias);
free(exec_ctx->history_command);
}

View File

@@ -1,29 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
char *insert_str(const char *base, const char *insert, size_t pos)
{
size_t base_len = strlen(base);
size_t insert_len = strlen(insert);
size_t new_len;
char *res;
if (pos >= base_len)
pos = base_len;
new_len = base_len - 1 + insert_len;
res = malloc(sizeof(char) * (new_len + 1));
if (res == nullptr)
return nullptr;
memcpy(res, base, pos);
strncpy(res + pos, insert, insert_len);
memcpy(res + pos + insert_len, base + pos + 1, base_len - pos - 1 + 1);
return res;
}

View File

@@ -1,20 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** is_a_token
*/
#include "string.h"
#include "u_str.h"
#include "ast.h"
bool is_a_token(char *str, int index_str)
{
str += index_str;
for (size_t i = 0; i < 16; i++) {
if (strncmp(str, TOKENS_LIST[i].str, TOKENS_LIST[i].sz) == 0){
return true;
}
}
return false;
}

View File

@@ -1,17 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** len_array
*/
#include <stdlib.h>
int len_array(char **array)
{
int i = 0;
while (array[i] != NULL)
i++;
return i;
}

View File

@@ -1,22 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** strn_to_ndup
*/
#include <stdlib.h>
char *strn_to_ndup(int start, int size, char *str)
{
char *new_str = malloc(sizeof(char) * (size + 1));
int count = 0;
if (new_str == NULL)
return NULL;
new_str[size] = '\0';
for (int i = start; i != start + size; i++){
new_str[count] = str[i];
count++;
}
return new_str;
}

View File

@@ -1,77 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <unistd.h>
#include "ast.h"
#include "common.h"
#include "debug.h"
#include "exec.h"
#include "u_str.h"
#include "visitor.h"
int visit_and(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
if (!node->binary.left || !node->binary.right)
return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"),
RETURN_FAILURE;
result = visit_condition(ef, node->binary.left);
if (!result)
result = visit_condition(ef, node->binary.right);
return result;
}
int visit_or(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
if (!node->binary.left || !node->binary.right)
return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"),
RETURN_FAILURE;
result = visit_condition(ef, node->binary.left);
if (result) {
ef->history->last_exit_code = 0;
result = visit_condition(ef, node->binary.right);
}
return result;
}
static
int visit_then(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
for (size_t i = 0; i < node->cond.sz; i++)
result = visit_expression(ef, node->cond.nodes[i]);
return result;
}
static
int visit_else(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
for (size_t i = 0; i < node->cond.sz2; i++)
result = visit_expression(ef, node->cond.nodes2[i]);
return result;
}
int visit_if(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
if (node->cond.sz < 1)
return WRITE_CONST(STDERR_FILENO, "Empty if.\n"),
RETURN_FAILURE;
result = visit_expression(ef, node->cond.exp);
U_DEBUG("If exp result [%d]\n", result);
if (result == RETURN_FAILURE)
return visit_else(ef, node);
return visit_then(ef, node);
}

View File

@@ -1,206 +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"
#include "visitor.h"
#include "debug.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;
}
int visit_list(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
if (node->type == N_CMD) {
ef->act_node = node;
return visit_cmd(ef);
}
if (node->tok.type == T_PIPE) {
ef->act_node = node;
return visit_pipes(ef);
}
return result;
}
int visit_condition(ef_t *ef, ast_t *node)
{
switch (node->tok.type) {
case T_AND:
return visit_and(ef, node);
case T_OR:
return visit_or(ef, node);
default:
return visit_list(ef, node);
}
}
static
int visit_semi(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
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]->tok.type & (T_AND | T_OR))
result = visit_condition(ef, node->list.nodes[i]);
if (node->list.nodes[i]->type == N_LST)
result = visit_list(ef, node->list.nodes[i]);
ef->pin_fd = STDIN_FILENO;
ef->pout_fd = STDOUT_FILENO;
if (node->list.nodes[i]->type == N_CMD)
result = visit_cmd(ef);
}
return result;
}
int visit_expression(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
if (node->tok.type & (T_SEMICOLON | T_NEWLINE))
result = visit_semi(ef, node);
if (node->tok.type & (T_AND | T_OR))
result = visit_condition(ef, node);
if (node->tok.type == T_PIPE)
result = visit_list(ef, node);
if (node->type == N_CMD) {
ef->act_node = node;
result = visit_cmd(ef);
}
return result;
}
//TODO: visit loop befor a visit list with a loop
static
int visitor_launcher(ef_t *ef)
{
ef->ctx->ast = parse_expression(ef->ctx);
if (ef->ctx->ast == NULL)
return RETURN_FAILURE;
U_DEBUG_CALL(print_ast, ef->ctx->ast, ef->ctx, 0);
return visit_expression(ef, ef->ctx->ast);
}
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';
if (str[len] == '\n')
str[len] = '\0';
}
}
int visitor(char *buffer, exec_ctx_t *exec_ctx)
{
ast_ctx_t ctx = { 0, .str = buffer,
.cap = u_strlen(buffer) + 10 + DEFAULT_AST_CAP,
.ast = malloc(sizeof *ctx.ast *
(u_strlen(buffer) + 10 + DEFAULT_AST_CAP)), .parsed_tok = 0 };
ef_t ef = { .buffer = buffer, .env = exec_ctx->env,
.history = exec_ctx->history, .ctx
= &ctx, .pout_fd = STDOUT_FILENO, .flags = 0,
.exec_ctx = exec_ctx};
int result = RETURN_FAILURE;
ctx.first_node = ctx.ast;
remove_trailing_semi(ctx.str);
exec_ctx->history->last_exit_code = 0;
if (ctx.ast == NULL)
return RETURN_FAILURE;
result = visitor_launcher(&ef);
if (ef.flags & F_EXIT)
builtins_exit(&ef, nullptr);
free_ast(&ctx);
return result == -1 ? RETURN_FAILURE : result;
}

View File

@@ -1,26 +0,0 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef VISITOR_H
#define VISITOR_H
#include "ast.h"
#include "exec.h"
// Main
int visit_expression(ef_t *ef, ast_t *node);
// List (pipe, ...)
int visit_list(ef_t *ef, ast_t *node);
// Conditions
int visit_if(ef_t *ef, ast_t *node);
int visit_and(ef_t *ef, ast_t *node);
int visit_or(ef_t *ef, ast_t *node);
int visit_condition(ef_t *ef, ast_t *node);
#endif /* VISITOR_H */

View File

@@ -1,30 +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"
// special
#define BLINKING_VERTICAL_CURSOR ESC "[5 q"
// 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

View File

@@ -158,6 +158,7 @@ bool check_for_closable(ast_t *node, exec_ctx_t *ctx, size_t *i, args_t *args)
void handle_var_case(ast_t *node, exec_ctx_t *ctx, size_t *i, args_t *args)
{
args->args[args->sz] = nullptr;
if (check_for_closable(node, ctx, i, args))
return;
handle_var(node, i, ctx, args);

View File

@@ -14,10 +14,10 @@
#include <termios.h>
#include <unistd.h>
#include "debug.h"
#include "readline.h"
#include "repl.h"
#include "u_str.h"
#include "vt100_esc_codes.h"
bool ensure_buff_av_capacity(buff_t *buff, size_t requested)
{
@@ -96,18 +96,12 @@ void write_buff(readline_helper_t *rh)
write(STDOUT_FILENO, move_back, strlen(move_back));
}
void refresh_line(readline_helper_t *rh)
static
void print_buff(readline_helper_t *rh)
{
size_t target = rh->cursor + rh->ec->prompt_len;
char move_cursor[32];
if (!rh->ec->isatty)
return;
append_null_terminator(rh->out);
if (rh->out->sz > 1 && *rh->cpy == '\n') {
WRITE_CONST(STDOUT_FILENO, "\n");
return;
}
WRITE_CONST(STDOUT_FILENO, "\r");
if (rh->ec->prompt_len > 0)
print_second_shell_prompt(rh->ec);
@@ -117,6 +111,22 @@ void refresh_line(readline_helper_t *rh)
write(STDOUT_FILENO, move_cursor, strlen(move_cursor));
}
void refresh_line(readline_helper_t *rh)
{
if (!rh->ec->isatty)
return;
append_null_terminator(rh->out);
if (rh->cursor + rh->ec->prompt_len > rh->winsz.ws_col) {
write(STDOUT_FILENO, rh->out->str + rh->cursor - 1, 1);
return;
}
if (rh->out->sz > 1 && *rh->cpy == '\n') {
WRITE_CONST(STDOUT_FILENO, "\n");
return;
}
print_buff(rh);
}
static
bool populate_copy_buff(
readline_helper_t *rh, ssize_t rd,
@@ -150,6 +160,8 @@ bool read_until_line_ending(
text_parse_info_t tpi;
for (;;) {
if (ec->isatty)
ioctl(STDOUT_FILENO, TIOCGWINSZ, &rh->winsz);
memset(&tpi, '\0', sizeof tpi);
if (!ensure_buff_av_capacity(rh->out, BULK_READ_BUFF_SZ))
return false;
@@ -174,6 +186,8 @@ bool readline(exec_ctx_t *ec, buff_t *out)
bool is_empty = true;
ssize_t rd = 0;
if (ec->isatty)
ioctl(STDOUT_FILENO, TIOCGWINSZ, &rh.winsz);
for (size_t i = 0; i < sizeof read_buff; i++)
is_empty &= read_buff[i] == '\0';
if (is_empty) {

View File

@@ -8,6 +8,7 @@
#ifndef READLINE
#define READLINE
#include <stdbool.h>
#include <sys/ioctl.h>
#include "builtins_handler.h"
#include "u_str.h"
@@ -22,6 +23,7 @@ typedef struct {
char cpy[BULK_READ_BUFF_SZ];
size_t cursor;
int history_idx;
struct winsize winsz;
} readline_helper_t;
typedef struct {