Merge branch 'main' into Line_edition_S

This commit is contained in:
savalet
2025-04-22 15:04:18 +02:00
30 changed files with 810 additions and 95 deletions

View File

@@ -22,7 +22,7 @@ jobs:
steps:
- name: Get branch name
id: branch-names
uses: tj-actions/branch-names@v6
uses: tj-actions/branch-names@v8
- uses: actions/checkout@v4
with:

View File

@@ -34,7 +34,7 @@ CFLAGS += -Wduplicated-cond -Wformat=2 -Wshadow -fno-builtin
CFLAGS += -Wstrict-aliasing=0 -Wstrict-prototypes -Wunreachable-code
CFLAGS += -Wwrite-strings -Werror=declaration-after-statement
CFLAGS += -Werror=format-nonliteral -Werror=int-conversion -Werror=return-type
CFLAGS += -Werror=vla-larger-than=0 -Wno-discarded-qualifiers
CFLAGS += -Wno-discarded-qualifiers
LDFLAGS += -L .
LDLIBS := -lu

59
README.md Normal file
View File

@@ -0,0 +1,59 @@
- [x] `:`
- [x] `alias`
- [ ] `alloc`
- [ ]`astprint`
- [x] `builtins`
- [x] `cd`/`chdir`
- [ ] `date`
- [ ] `echo`
- [x] `env`/`setenv`/`unsetenv` (`env` à completer)
- [ ] `export`
- [ ] `eval`/`exec`
- [x] `exit`
- [ ] `kill`
- [ ] `limit`
- [x] `printenv`
- [x] `pushd`/`popd`
- [ ] `printf`
- [x] `repeat`
- [ ] `source`/`.`
- [ ] `termname`
- [ ] `time`
- [ ] `trap`
- [ ] `wc`
- [ ] `which`/`where`
- [x] `yes`
- [x] pipes
- [x] redirections
- [ ] line editing (move, del, multi-line)
- [ ] input shortcut (^A,^E,^R,^V,^F,^B,...)
- [ ] color highlighting in input
- [ ] foreground/background jobs (`&`), (btln `fg`, `bg`, `jobs`)
- [ ] while/for/foreach loops
- [ ] if / cases
- [x] `||`/`&&`
- [ ] configuration file
- [x] script with shebangs
- [ ] `-c` eval argument
- [ ] `-D` set env var at boot
- [ ] `-e` exit on failure
- [ ] `-n` (dry run mode)
- [ ] `-h` help (open man?)
- [ ] autocompletion of commands
- [x] globbing (*)
- [ ] globbing
- [ ] var interpreter
- [ ] inhibitor
- [ ] magic quotes
- [ ] parenthesis (sub-commands)
- [ ] direnv/wakatime integration
- [x] command history (`history` btln)
- [ ] arithmetric expansion (`$(( x + 1 ))`)
- [ ] brace expansion: `{a,b,c}` and `{1..10}`
- [x] heredocs
- [ ] functions (`:() { :|:& }`)
- [ ] special env vars: `$?`, `$$`, ...
- [ ] git integration (branch)
- [ ] `x`, `e`, `o` & pipefail modes
- [ ] file inquiry operators (`-d`, `f`, ...)

5
iftest.sh Normal file
View File

@@ -0,0 +1,5 @@
if ls
echo YES
else
echo NO
endif

23
src/alias.h Normal file
View File

@@ -0,0 +1,23 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef ALIAS_H
#define ALIAS_H
#include "env.h"
#include "history.h"
#include "shell.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);
#endif /* ALIAS*/

View File

@@ -9,10 +9,14 @@
#define AST_H
#include <stddef.h>
#include <stdint.h>
#include "shell.h"
#include "builtins_handler.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 IF_PROMPT "if? "
#define T_ALL 0xff
typedef enum {
@@ -34,16 +38,21 @@ typedef enum {
T_AT = 1 << 15, // <
T_WHILE = 1 << 16, // while
T_FOREACH = 1 << 17, // foreach
T_EOF = 1 << 18, // \0
T_ARG = 1 << 19,
T_INVALID = 1 << 20
T_IF = 1 << 18, // if
T_THEN = 1 << 19, // then
T_ELSE = 1 << 20, // else
T_ENDIF = 1 << 21, // endif
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_LOP,
N_COND
} node_type_t;
typedef struct {
@@ -84,6 +93,15 @@ typedef struct ast_s {
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;
@@ -110,6 +128,8 @@ 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);
@@ -118,7 +138,9 @@ 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);
#endif /* AST_H */

View File

@@ -39,7 +39,7 @@ ast_t *fill_cmd_node(ast_ctx_t *ctx)
if (node == NULL)
return NULL;
node->type = N_CMD;
node->vector.cap = 2;
node->vector.cap = DEFAULT_N_CMD_CAP;
node->vector.tokens =
malloc(sizeof *node->vector.tokens * node->vector.cap);
if (node->vector.tokens == NULL)
@@ -87,7 +87,7 @@ ast_t *parse_pipe(ast_ctx_t *ctx, ast_t *l_node)
return NULL;
node->type = N_LST;
node->tok = ctx->act_tok;
node->list.cap = 2;
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 NULL;
@@ -121,7 +121,6 @@ ast_t *parse_condition(ast_ctx_t *ctx)
return ctx->ast;
}
static
ast_t *parse_semi(ast_ctx_t *ctx)
{
ast_t *l_node = parse_condition(ctx);
@@ -149,7 +148,7 @@ ast_t *create_semi_node(ast_ctx_t *ctx, ast_t *l_node)
if (node == NULL)
return NULL;
node->type = N_LST;
node->list.cap = 2;
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 NULL;
@@ -183,7 +182,10 @@ ast_t *parse_expression(ast_ctx_t *ctx)
if (ctx->act_tok.type == T_EOF)
return ctx->ast;
ctx->act_tok = get_next_token(ctx);
skip_semi(ctx);
if (ctx->act_tok.type == T_IF)
return parse_if(ctx);
l_node = parse_semi(ctx);
if (l_node == NULL)
return ctx->ast;
@@ -193,6 +195,5 @@ ast_t *parse_expression(ast_ctx_t *ctx)
return NULL;
ctx->ast = fill_semi_node(ctx, node);
}
ctx->act_tok = get_next_token(ctx);
return parse_expression(ctx);
}

75
src/ast/ast_cap.c Normal file
View File

@@ -0,0 +1,75 @@
/*
** 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

@@ -10,9 +10,7 @@
#include <unistd.h>
#include "ast.h"
#include "debug.h"
#include "u_mem.h"
#include "u_str.h"
void print_ast(ast_t *ast, ast_ctx_t *ctx, size_t depth)
{
@@ -55,38 +53,6 @@ ast_t *create_node(ast_ctx_t *ctx)
return ctx->ast + ctx->sz - 1;
}
bool ensure_node_cap(ast_t *node)
{
token_t *temp;
if (node->vector.sz + 1 < node->vector.cap)
return true;
temp = u_realloc(node->vector.tokens,
sizeof *node->vector.tokens * node->vector.sz,
sizeof *node->vector.tokens * node->vector.cap << 1);
if (temp == NULL)
return false;
node->vector.cap <<= 1;
node->vector.tokens = temp;
return true;
}
bool ensure_list_cap(ast_t *node)
{
ast_t **temp;
if (node->list.sz + 1 < node->vector.cap)
return true;
temp = (ast_t **)u_realloc((void *)node->list.nodes,
sizeof *node->list.nodes * node->list.sz,
sizeof *node->list.nodes * node->vector.cap << 1);
if ((void *)temp == NULL)
return false;
node->list.cap <<= 1;
node->list.nodes = temp;
return true;
}
void free_ast(ast_ctx_t *ctx)
{
for (size_t i = 0; i < ctx->sz; i++) {

View File

@@ -5,7 +5,13 @@
** _
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ast.h"
#include "u_str.h"
ast_t *parse_and(ast_ctx_t *ctx, ast_t *l_node)
{
@@ -16,7 +22,7 @@ ast_t *parse_and(ast_ctx_t *ctx, ast_t *l_node)
node->tok = ctx->act_tok;
node->type = N_BIN;
node->binary.left = l_node;
node->binary.right = parse_condition(ctx);
node->binary.right = parse_semi(ctx);
if (node->binary.right == NULL)
return NULL;
return node;
@@ -31,8 +37,86 @@ ast_t *parse_or(ast_ctx_t *ctx, ast_t *l_node)
node->tok = ctx->act_tok;
node->type = N_BIN;
node->binary.left = l_node;
node->binary.right = parse_condition(ctx);
node->binary.right = parse_semi(ctx);
if (node->binary.right == NULL)
return NULL;
return node;
}
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++;
if (!ensure_cond_cap2(node))
return false;
return true;
}
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++;
if (!ensure_cond_cap(node))
return false;
return true;
}
static
ast_t *fill_if(ast_ctx_t *ctx, ast_t *node)
{
buff_t buff = { .str = NULL, 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 NULL;
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 NULL;
buff = (buff_t){ .str = NULL, 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 NULL;
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 NULL;
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

@@ -101,7 +101,6 @@ ast_t *get_usr_loop_cmd(ast_t *node)
return node;
}
static
void exit_child(int sig __attribute__((unused)))
{
_exit(sig);

View File

@@ -30,7 +30,10 @@ const tokens_list_t TOKENS_LIST[] = {
{ T_HEREDOC, "<<", 2, "T_HEREDOC" },
{ T_IN_REDIRECT, "<", 1, "T_IN_REDIRECT" },
{ T_WHILE, "while", 5, "T_WHILE"},
{ T_FOREACH, "foreach", 7, "T_WHILE"},
{ T_IF, "if", 2, "T_IF"},
{ T_THEN, "then", 4, "T_THEN"},
{ T_ELSE, "else", 4, "T_ELSE"},
{ T_ENDIF, "endif", 5, "T_ENDIF"},
{ T_EOF, "\0", 1, "T_EOF" }
};
@@ -50,11 +53,9 @@ bool parser_eat(ast_ctx_t *ctx, token_type_t expected)
if (!(ctx->act_tok.type & expected)) {
if (prev_tok_type == T_PIPE)
WRITE_CONST(STDERR_FILENO, "Invalid null command.\n");
else {
WRITE_CONST(STDERR_FILENO, "Parse error near \"");
write(STDERR_FILENO, ctx->act_tok.str, ctx->act_tok.sz);
WRITE_CONST(STDERR_FILENO, "\"\n");
}
else
dprintf(STDERR_FILENO, "Parse error near \"%.*s\"\n",
(int)ctx->ast->tok.sz, ctx->ast->tok.str);
return false;
}
return true;

View File

@@ -26,4 +26,8 @@ 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);
#endif /* BUILTIND_H */

View File

@@ -0,0 +1,110 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** history
*/
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "common.h"
#include "env.h"
#include "exec.h"
#include "alias.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(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 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;
}

56
src/builtins/repeat.c Normal file
View File

@@ -0,0 +1,56 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** repeat
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#include "builtins.h"
#include "common.h"
#include "exec.h"
#include "u_str.h"
static
bool checking_error(ef_t *ef, 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(ef, 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;
}

68
src/builtins/yes.c Normal file
View File

@@ -0,0 +1,68 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** yes
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#include "builtins.h"
#include "common.h"
#include "exec.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 = NULL;
if (args[1] == NULL)
return u_strdup("y\n");
buffer = malloc(sizeof(char) * (len_buffer(args) + 1));
if (buffer == NULL)
return NULL;
strcpy(buffer, args[1]);
for (int i = 2; args[i]; i++){
strcat(buffer, args[i]);
if (args[i + 1] != NULL)
buffer[strlen(buffer) - 1] = ' ';
}
buffer[strlen(buffer) - 1] = '\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){
while (true){
signal(SIGINT, exit_child);
write(ef->out_fd, buffer, strlen(buffer));
}
exit(RETURN_SUCCESS);
} else
wait(NULL);
free(buffer);
return RETURN_SUCCESS;
}

View File

@@ -11,11 +11,13 @@
#include "env.h"
#include "history.h"
#include "shell.h"
#include "alias.h"
typedef struct {
env_t *env;
history_t *history;
his_command_t *history_command;
alias_t *alias;
} exec_ctx_t;
size_t update_command(char **buffer,

View File

@@ -22,6 +22,7 @@
#include "path.h"
#include "u_mem.h"
#include "u_str.h"
#include "alias.h"
const builtins_funcs_t BUILTINS[] = {
{ "builtins", &builtins_builtins },
@@ -32,8 +33,11 @@ const builtins_funcs_t BUILTINS[] = {
{ "setenv", &builtins_setenv },
{ "unsetenv", &builtins_unsetenv },
{ ":", &builtins_funny_double_dot },
{ "repeat", &builtins_repeat },
{ "exit", &builtins_exit },
{ "history", &builtins_history}
{ "history", &builtins_history},
{ "alias", &builtins_alias},
{ "yes", &builtins_yes }
};
const size_t BUILTINS_SZ = sizeof BUILTINS / sizeof *BUILTINS;
@@ -180,15 +184,11 @@ bool builtins_launcher(ef_t *ef, char **args)
return false;
}
int execute(ef_t *ef)
int exec_the_args(ef_t *ef, char **args)
{
char *full_bin_path;
char **args;
int status;
args = parse_args(ef, ef->act_node, ef->env);
if (!args)
return RETURN_FAILURE;
if (builtins_launcher(ef, args))
return RETURN_SUCCESS;
full_bin_path = parse_full_bin_path(ef->env, args[0]);
@@ -199,6 +199,17 @@ int execute(ef_t *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, ef->env);
if (!args)
return RETURN_FAILURE;
exec_the_args(ef, args);
free((void *)args);
return ef->exec_ctx->history->last_exit_code
!= 0 ? RETURN_FAILURE : RETURN_SUCCESS;

View File

@@ -48,6 +48,8 @@ typedef struct {
__attribute__((nonnull))
int execute(ef_t *ef);
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);
char *handle_var_case(ast_t *node, env_t *env, size_t *i);
#endif /* EXEC_H */

97
src/parse_alias.c Normal file
View File

@@ -0,0 +1,97 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** parse_alias
*/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "utils.h"
#include "common.h"
#include "env.h"
#include "exec.h"
#include "u_mem.h"
#include "u_str.h"
#include "history.h"
#include "alias.h"
static int skip_blank(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) == false; i++);
return i;
}
static
char *find_alias(his_variable_t *variable, alias_t *alias, char *buffer)
{
char cmd[variable->size_variable + 1];
char *new_cmd = NULL;
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 NULL;
if (strcmp(cmd, alias->alias_array[i]) == 0){
new_cmd = cat_in_str(variable, buffer, alias->alias_to_replace[i]);
free(buffer);
buffer = new_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, NULL, 0};
for (; buffer[i] != 0 && !isblank(buffer[i])
&& is_a_token(buffer, i) == false; 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 == true)
need_to_replace = replace_alias(buffer, alias);
return RETURN_SUCCESS;
}

View File

@@ -60,11 +60,14 @@ static
bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx)
{
char *tmp_buff = NULL;
size_t buff_len;
if (!readline(buff))
return true;
tmp_buff = buff->str;
buff->sz = update_command(&tmp_buff, &buff->sz, exec_ctx);
buff_len = update_command(&tmp_buff, &buff->sz, exec_ctx);
if (!buff_len)
return false;
if (buff->sz < 1 || !u_str_is_alnum(tmp_buff)) {
check_basic_error(tmp_buff);
free(tmp_buff);
@@ -108,7 +111,11 @@ his_command_t *init_cmd_history(void)
static
bool error_in_init(exec_ctx_t *exec_ctx)
{
if (!exec_ctx->history_command || !exec_ctx->env->env) {
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;
@@ -116,13 +123,29 @@ bool error_in_init(exec_ctx_t *exec_ctx)
return false;
}
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] = NULL;
alias.alias_to_replace[0] = NULL;
alias.size = 0;
return alias;
}
int shell(char **env_ptr)
{
alias_t alias = init_alias();
env_t env = parse_env(env_ptr);
history_t history = { .cmd_history = NULL, 0, .last_chdir = NULL};
his_command_t *cmd_history = init_cmd_history();
exec_ctx_t exec_ctx = {.env = &env,
.history = &history, .history_command = cmd_history };
.history = &history, .history_command = cmd_history, .alias = &alias};
int shell_result;
if (error_in_init(&exec_ctx) == true){
@@ -131,6 +154,9 @@ int shell(char **env_ptr)
U_DEBUG_CALL(debug_env_entries, &env);
signal(SIGINT, ignore_sigint);
shell_result = shell_loop(isatty(STDIN_FILENO), &exec_ctx);
if (isatty(STDIN_FILENO))
WRITE_CONST(STDOUT_FILENO, "exit\n");
free_env(exec_ctx.env);
free_alias(exec_ctx.alias);
return shell_result;
}

View File

@@ -7,6 +7,7 @@
#include "history.h"
#include "builtins_handler.h"
#include "u_str.h"
#include "common.h"
static int check_cmd(char *cmd)
{
@@ -39,11 +40,12 @@ size_t update_command(char **buffer,
buffer_len = u_strlen(*buffer);
if (buffer_len < 2)
return 1;
return RETURN_FAILURE;
(*buffer)[buffer_len - 1] = '\0';
if (parse_history(buffer, &buffer_len,
buffer_sz, &exec_ctx->history_command) == 84)
return -1;
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

@@ -11,7 +11,7 @@
static
int insert_in_str(char *dest, char *cpy, int start)
{
for (int j = 0; cpy[j] != 0; j++){
for (int j = 0; cpy[j] != '\0'; j++){
dest[start] = cpy[j];
start++;
}
@@ -32,7 +32,7 @@ char *cat_in_str(his_variable_t *his_variable, char *str, char *cpy)
return NULL;
for (; i < size_left; i++)
new_str[i] = str[i];
i += insert_in_str(new_str, cpy, 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++;

View File

@@ -12,7 +12,7 @@ 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, 2) == 0){
if (strncmp(str, TOKENS_LIST[i].str, TOKENS_LIST[i].sz) == 0){
return true;
}
}

View File

@@ -9,6 +9,7 @@
#include "ast.h"
#include "common.h"
#include "debug.h"
#include "exec.h"
#include "u_str.h"
#include "visitor.h"
@@ -21,8 +22,12 @@ int visit_and(ef_t *ef, ast_t *node)
return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"),
RETURN_FAILURE;
result = visit_list(ef, node->binary.left);
if (!result)
result = visit_list(ef, node->binary.right);
if (!result) {
if (node->binary.right->tok.type & (T_AND | T_OR))
result = visit_condition(ef, node->binary.right);
else
result = visit_list(ef, node->binary.right);
}
return result;
}
@@ -34,7 +39,46 @@ int visit_or(ef_t *ef, ast_t *node)
return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"),
RETURN_FAILURE;
result = visit_list(ef, node->binary.left);
if (result)
result = visit_list(ef, node->binary.right);
if (result) {
ef->history->last_exit_code = 0;
if (node->binary.right->tok.type & (T_AND | T_OR))
result = visit_condition(ef, node->binary.right);
else
result = visit_list(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

@@ -108,14 +108,18 @@ int visit_list(ef_t *ef, ast_t *node)
return result;
}
static
int visit_condition(ef_t *ef, ast_t *node)
{
if (node->tok.type == T_AND)
return visit_and(ef, node);
if (node->tok.type == T_OR)
return visit_or(ef, node);
return RETURN_FAILURE;
switch (node->tok.type) {
case T_IF:
return visit_if(ef, node);
case T_AND:
return visit_and(ef, node);
case T_OR:
return visit_or(ef, node);
default:
return RETURN_FAILURE;
}
}
static
@@ -138,30 +142,34 @@ int visit_semi(ef_t *ef, ast_t *node)
return result;
}
int visit_expression(ef_t *ef, ast_t *node)
{
int result = RETURN_FAILURE;
if (node->type == N_LOP)
result = visit_loop(ef, node);
if (node->tok.type == T_SEMICOLON)
result = visit_semi(ef, node);
if (node->tok.type & (T_IF | 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)
{
int result = RETURN_FAILURE;
ef->ctx->act_tok = get_next_token(ef->ctx);
ef->ctx->ast = parse_expression(ef->ctx);
if (ef->ctx->ast == NULL)
return RETURN_FAILURE;
U_DEBUG_CALL(print_ast, ef->ctx->ast, ef->ctx, 0);
if (ef->ctx->ast->type == N_LOP)
result = visit_loop(ef, ef->ctx->ast);
if (ef->ctx->ast->tok.type == T_SEMICOLON)
result = visit_semi(ef, ef->ctx->ast);
if (ef->ctx->ast->tok.type & (T_AND | T_OR))
result = visit_condition(ef, ef->ctx->ast);
if (ef->ctx->ast->tok.type == T_PIPE)
result = visit_list(ef, ef->ctx->ast);
if (ef->ctx->ast->type == N_CMD) {
ef->act_node = ef->ctx->ast;
result = visit_cmd(ef);
}
return result;
return visit_expression(ef, ef->ctx->ast);
}
static

View File

@@ -10,10 +10,17 @@
#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 */

24
ulib/str/arraydup.c Normal file
View File

@@ -0,0 +1,24 @@
/*
** EPITECH PROJECT, 2025
** minish
** File description:
** arraydup
*/
#include "u_str.h"
#include <stdlib.h>
char **arraydup(char **array)
{
char **dup_array = NULL;
int i = 0;
if (array == NULL)
return NULL;
dup_array = malloc(sizeof(char *) * (my_array_len(array) + 1));
if (dup_array == NULL)
return NULL;
for (; array[i] != NULL; i++)
dup_array[i] = u_strdup(array[i]);
dup_array[i] = NULL;
return dup_array;
}

17
ulib/str/my_array_len.c Normal file
View File

@@ -0,0 +1,17 @@
/*
** EPITECH PROJECT, 2024
** Semester_1
** File description:
** my_array_len
*/
#include <unistd.h>
int my_array_len(char **tab)
{
int count = 0;
if (tab == NULL)
return count;
for (; tab[count] != NULL; count++);
return count;
}

View File

@@ -35,5 +35,7 @@ bool u_str_is_alnum(char *str);
bool u_str_is_only_alnum(char *str);
void free_array(char **array);
void puterror(char const *prefix);
int my_array_len(char **tab);
char **arraydup(char **array);
#endif /* STRING_H */