mirror of
https://github.com/Savapitech/42sh.git
synced 2026-01-18 16:57:28 +01:00
Fix multi line
This commit is contained in:
2
FIX.md
2
FIX.md
@@ -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
|
||||
|
||||
9
Makefile
9
Makefile
@@ -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)
|
||||
|
||||
|
||||
111
bonus/alias.c
111
bonus/alias.c
@@ -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;
|
||||
}
|
||||
@@ -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*/
|
||||
90
bonus/args.c
90
bonus/args.c
@@ -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;
|
||||
}
|
||||
24
bonus/args.h
24
bonus/args.h
@@ -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 */
|
||||
147
bonus/ast.h
147
bonus/ast.h
@@ -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 */
|
||||
192
bonus/ast/ast.c
192
bonus/ast/ast.c
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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) };
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
47
bonus/ctx.h
47
bonus/ctx.h
@@ -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 */
|
||||
@@ -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 */
|
||||
149
bonus/env.c
149
bonus/env.c
@@ -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;
|
||||
}
|
||||
30
bonus/env.h
30
bonus/env.h
@@ -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
|
||||
236
bonus/exec.c
236
bonus/exec.c
@@ -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;
|
||||
}
|
||||
60
bonus/exec.h
60
bonus/exec.h
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
82
bonus/job.c
82
bonus/job.c
@@ -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;
|
||||
}
|
||||
19
bonus/job.h
19
bonus/job.h
@@ -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 */
|
||||
@@ -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 */
|
||||
23
bonus/loop.h
23
bonus/loop.h
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
57
bonus/main.c
57
bonus/main.c
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
68
bonus/path.c
68
bonus/path.c
@@ -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;
|
||||
}
|
||||
15
bonus/path.h
15
bonus/path.h
@@ -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
|
||||
119
bonus/readline.c
119
bonus/readline.c
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
81
bonus/repl.c
81
bonus/repl.c
@@ -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;
|
||||
}
|
||||
}
|
||||
18
bonus/repl.h
18
bonus/repl.h
@@ -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 */
|
||||
151
bonus/shell.c
151
bonus/shell.c
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
206
bonus/visitor.c
206
bonus/visitor.c
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user