mirror of
https://github.com/Savapitech/42sh.git
synced 2026-01-18 16:57:28 +01:00
Merge branch 'main' into Line_edition_S
This commit is contained in:
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -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:
|
||||
|
||||
2
Makefile
2
Makefile
@@ -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
59
README.md
Normal 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`, ...)
|
||||
23
src/alias.h
Normal file
23
src/alias.h
Normal 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*/
|
||||
32
src/ast.h
32
src/ast.h
@@ -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 */
|
||||
|
||||
@@ -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
75
src/ast/ast_cap.c
Normal 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;
|
||||
}
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
110
src/builtins/builtins_alias.c
Normal file
110
src/builtins/builtins_alias.c
Normal 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
56
src/builtins/repeat.c
Normal 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
68
src/builtins/yes.c
Normal 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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
23
src/exec.c
23
src/exec.c
@@ -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;
|
||||
|
||||
@@ -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
97
src/parse_alias.c
Normal 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;
|
||||
}
|
||||
32
src/shell.c
32
src/shell.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
24
ulib/str/arraydup.c
Normal 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
17
ulib/str/my_array_len.c
Normal 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;
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user