From 7f655e4dc60d748e8c39dedc77f1f94a6fc0956e Mon Sep 17 00:00:00 2001 From: savalet Date: Fri, 2 May 2025 17:34:23 +0200 Subject: [PATCH 01/46] Change && and || parsing order --- src/ast/ast.c | 81 +++++++++++++++++++++++--------------------- src/ast/ast_utils.c | 2 +- src/ast/conditions.c | 10 +++--- src/ast/tokeniser.c | 2 +- 4 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/ast/ast.c b/src/ast/ast.c index b889782..d41fc0d 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -29,7 +29,7 @@ ast_t *parse_arg(ast_ctx_t *ctx, ast_t *node) if (ctx->act_tok.type & (T_ARG | T_REDIRECT | T_APPEND | T_IN_REDIRECT | T_HEREDOC | T_VAR | T_STAR)) { if (!ensure_node_cap(node)) - return NULL; + return nullptr; node->vector.tokens[node->vector.sz] = ctx->act_tok; node->vector.sz++; return parse_arg(ctx, node); @@ -43,13 +43,13 @@ ast_t *fill_cmd_node(ast_ctx_t *ctx) ast_t *node = create_node(ctx); if (node == NULL) - return 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 NULL; + return nullptr; node->tok = ctx->act_tok; node->vector.tokens[0] = ctx->act_tok; node->vector.sz = 1; @@ -67,9 +67,9 @@ ast_t *parse_cmd(ast_ctx_t *ctx) { if (ctx->act_tok.type != T_ARG) { if (ctx->act_tok.type & (T_WHILE)) - return NULL; + return nullptr; if (!parser_eat(ctx, T_ARG)) - return NULL; + return nullptr; } return fill_cmd_node(ctx); } @@ -91,20 +91,20 @@ ast_t *parse_pipe(ast_ctx_t *ctx, ast_t *l_node) ast_t *node = create_node(ctx); if (node == NULL) - return 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 NULL; + return nullptr; node->list.sz = 1; node->list.nodes[0] = l_node; if (!parser_eat(ctx, T_ARG)) - return NULL; + return nullptr; while (ctx->act_tok.type & (T_ARG | T_PIPE)) if (!parse_pipe_childs(ctx, node)) - return NULL; + return nullptr; return node; } @@ -113,31 +113,10 @@ ast_t *parse_condition(ast_ctx_t *ctx) ast_t *l_node = parse_cmd(ctx); if (l_node == NULL) - return NULL; - else { - switch (ctx->act_tok.type) { - case T_PIPE: - ctx->ast = parse_pipe(ctx, l_node); - break; - default: - return l_node; - } - } - return ctx->ast; -} - -ast_t *parse_semi(ast_ctx_t *ctx) -{ - ast_t *l_node = parse_condition(ctx); - - if (l_node == NULL) - return NULL; + return nullptr; switch (ctx->act_tok.type) { - case T_AND: - ctx->ast = parse_and(ctx, l_node); - break; - case T_OR: - ctx->ast = parse_or(ctx, l_node); + case T_PIPE: + ctx->ast = parse_pipe(ctx, l_node); break; default: return l_node; @@ -145,18 +124,44 @@ ast_t *parse_semi(ast_ctx_t *ctx) return ctx->ast; } +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_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 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 NULL; + return nullptr; node->list.sz = 1; node->list.nodes[0] = l_node; node->tok = ctx->act_tok; @@ -171,10 +176,10 @@ ast_t *fill_semi_node(ast_ctx_t *ctx, ast_t *node) if (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE)) continue; if (!ensure_list_cap(node)) - return NULL; + return nullptr; node->list.nodes[node->list.sz] = parse_semi(ctx); if (node->list.nodes[node->list.sz] == NULL) - return NULL; + return nullptr; node->list.sz++; } return node; @@ -195,7 +200,7 @@ ast_t *parse_expression(ast_ctx_t *ctx) if (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE)) { node = create_semi_node(ctx, l_node); if (node == NULL) - return NULL; + return nullptr; ctx->ast = fill_semi_node(ctx, node); } return parse_expression(ctx); diff --git a/src/ast/ast_utils.c b/src/ast/ast_utils.c index 4f2dec0..35d5f5a 100644 --- a/src/ast/ast_utils.c +++ b/src/ast/ast_utils.c @@ -24,7 +24,7 @@ void print_ast(ast_t *ast, ast_ctx_t *ctx, size_t depth) print_ast(ast->binary.right, ctx, depth + 1); } if (ast->type == N_CMD) { - for (size_t i = 0; i < ast->vector.sz; i++) + 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); } diff --git a/src/ast/conditions.c b/src/ast/conditions.c index 7b9e722..0124d3a 100644 --- a/src/ast/conditions.c +++ b/src/ast/conditions.c @@ -19,13 +19,13 @@ 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 NULL; + return nullptr; node->tok = ctx->act_tok; node->type = N_BIN; node->binary.left = l_node; - node->binary.right = parse_semi(ctx); + node->binary.right = parse_condition_and(ctx); if (node->binary.right == NULL) - return NULL; + return nullptr; return node; } @@ -34,13 +34,13 @@ 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 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 NULL; + return nullptr; return node; } diff --git a/src/ast/tokeniser.c b/src/ast/tokeniser.c index a96ec7e..60501cb 100644 --- a/src/ast/tokeniser.c +++ b/src/ast/tokeniser.c @@ -141,7 +141,7 @@ token_t get_next_token(ast_ctx_t *ctx) 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]%d\n", (int)(ctx->str - start), start); + 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) }; } From d6be23437dea434813321614315de47f414d547d Mon Sep 17 00:00:00 2001 From: savalet Date: Fri, 2 May 2025 17:34:42 +0200 Subject: [PATCH 02/46] && and || can now visit condition with the left node --- src/ast.h | 1 + src/visit_condition.c | 21 ++++++--------------- src/visitor.c | 2 +- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/ast.h b/src/ast.h index c7169cd..aaa6217 100644 --- a/src/ast.h +++ b/src/ast.h @@ -139,4 +139,5 @@ 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); #endif /* AST_H */ diff --git a/src/visit_condition.c b/src/visit_condition.c index 83e7cf0..e331d90 100644 --- a/src/visit_condition.c +++ b/src/visit_condition.c @@ -21,13 +21,9 @@ int visit_and(ef_t *ef, ast_t *node) if (!node->binary.left || !node->binary.right) return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"), RETURN_FAILURE; - result = visit_list(ef, node->binary.left); - if (!result) { - if (node->binary.right->tok.type & (T_AND | T_OR)) - result = visit_condition(ef, node->binary.right); - else - result = visit_list(ef, node->binary.right); - } + result = visit_condition(ef, node->binary.left); + if (!result) + result = visit_condition(ef, node->binary.right); return result; } @@ -38,14 +34,9 @@ int visit_or(ef_t *ef, ast_t *node) if (!node->binary.left || !node->binary.right) return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"), RETURN_FAILURE; - result = visit_list(ef, node->binary.left); - if (result) { - ef->history->last_exit_code = 0; - if (node->binary.right->tok.type & (T_AND | T_OR)) - result = visit_condition(ef, node->binary.right); - else - result = visit_list(ef, node->binary.right); - } + result = visit_condition(ef, node->binary.left); + if (result) + result = visit_condition(ef, node->binary.right); return result; } diff --git a/src/visitor.c b/src/visitor.c index 4625179..f532f38 100644 --- a/src/visitor.c +++ b/src/visitor.c @@ -116,7 +116,7 @@ int visit_condition(ef_t *ef, ast_t *node) case T_OR: return visit_or(ef, node); default: - return RETURN_FAILURE; + return visit_list(ef, node); } } From 17dd638fc65227e991fa560abba50b33952ae6d9 Mon Sep 17 00:00:00 2001 From: savalet Date: Fri, 2 May 2025 17:36:08 +0200 Subject: [PATCH 03/46] Fix || exit code --- src/visit_condition.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/visit_condition.c b/src/visit_condition.c index e331d90..fcf78fa 100644 --- a/src/visit_condition.c +++ b/src/visit_condition.c @@ -35,8 +35,10 @@ int visit_or(ef_t *ef, ast_t *node) return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"), RETURN_FAILURE; result = visit_condition(ef, node->binary.left); - if (result) + if (result) { + ef->history->last_exit_code = 0; result = visit_condition(ef, node->binary.right); + } return result; } From c34e00f8de6922e45d0874b50a7f57590d57c90a Mon Sep 17 00:00:00 2001 From: savalet Date: Fri, 2 May 2025 17:37:11 +0200 Subject: [PATCH 04/46] Add && and || tests --- validation_tests.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validation_tests.py b/validation_tests.py index 1490448..d0c3b83 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -196,6 +196,11 @@ TESTS = [ "aa||aa\n", "ls||aa\n", "&&\n", + "ls && ls || ls && ls\n", + "ls && ls a || ls && ls\n", + "ls && ls || ls && ls a\n", + "ls && ls || ls && a\n", + "ls aa && ls || ls\n", ], depends_on=() ), From 2824ad315ce988b3615a40587500e0172b27f6ac Mon Sep 17 00:00:00 2001 From: savalet Date: Fri, 2 May 2025 17:40:37 +0200 Subject: [PATCH 05/46] Fix ast cs --- src/ast/ast.c | 13 ------------- src/ast/conditions.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ast/ast.c b/src/ast/ast.c index d41fc0d..44c6cf5 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -124,19 +124,6 @@ ast_t *parse_condition(ast_ctx_t *ctx) return ctx->ast; } -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_semi(ast_ctx_t *ctx) { ast_t *l_node = parse_condition_and(ctx); diff --git a/src/ast/conditions.c b/src/ast/conditions.c index 0124d3a..e0879a1 100644 --- a/src/ast/conditions.c +++ b/src/ast/conditions.c @@ -44,6 +44,19 @@ ast_t *parse_or(ast_ctx_t *ctx, ast_t *l_node) 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; +} + static bool fill_else_node(ast_ctx_t *ctx, ast_t *node, buff_t *buff) { From d3c6319faa2787964f2dc306f21772221f8dbffd Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 16:51:49 +0200 Subject: [PATCH 06/46] Add if --- src/builtins/if.c | 135 +++++++++++++++++++++++++++++++++++++--------- src/shell.c | 19 +++---- 2 files changed, 117 insertions(+), 37 deletions(-) diff --git a/src/builtins/if.c b/src/builtins/if.c index 7a4ed34..877c94d 100644 --- a/src/builtins/if.c +++ b/src/builtins/if.c @@ -16,13 +16,24 @@ #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; + static int get_argc(char **args) { int i = 0; - for (; *args != NULL; args++) - i++; + for (; args[i]; i++); return i; } @@ -33,8 +44,8 @@ bool ensure_cmds_cap(char ***cmd, size_t sz, size_t *cap) if (sz + 1 < *cap) return true; - tmp = (char **)realloc((void *)*cmd, sizeof(**cmd) * *cap << 1); - if (tmp == nullptr) + tmp = (char **)realloc(*cmd, sizeof(char *) * (*cap << 1)); + if (!tmp) return false; *cap <<= 1; *cmd = tmp; @@ -42,50 +53,122 @@ bool ensure_cmds_cap(char ***cmd, size_t sz, size_t *cap) } static -bool if_repl(ef_t *ef, char **args, char *cmd) +bool init_block(cmd_block_t *blk) { - buff_t buff = { .str = nullptr, 0 }; - char **cmds; - size_t cap = DEFAULT_N_CMD_CAP; - size_t sz = 0; + blk->size = 0; + blk->cap = DEFAULT_N_CMD_CAP; + blk->cmds = (char **)malloc(sizeof(char *) * blk->cap); + return blk->cmds != NULL; +} - if (strcmp("then", cmd) != 0) - return visitor(cmd, ef->exec_ctx), true; - cmds = (char **)malloc(cap * sizeof(char **)); - if ((void *)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(if_ctx_t *ctx, cmd_block_t *then_blk, + cmd_block_t *else_blk) +{ + bool in_else = false; + while (true) { if (isatty(STDIN_FILENO)) - WRITE_CONST(ef->out_fd, IF_PROMPT); - if (getline(&buff.str, &buff.sz, stdin) == -1) - break; - if (!ensure_cmds_cap(&cmds, sz, &cap)) + 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; - cmds[sz] = strdup(buff.str); } 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) +{ + if_ctx_t ctx = {.buff = &(buff_t){ .str = nullptr, .sz = 0 }, .ef = ef}; + cmd_block_t then_blk; + cmd_block_t else_blk; + + if (!init_block(&then_blk) || !init_block(&else_blk)) + return false; + if (!read_if_blocks(&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 *cmd; + 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; - cmd = strdup(args[get_argc(args) - 1]); - if (cmd == NULL) + 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(cmd), RETURN_FAILURE; - if (result) - if (!if_repl(ef, args, cmd)) - return free(cmd), RETURN_FAILURE; - return free(cmd), RETURN_SUCCESS; + return free(last), RETURN_FAILURE; + if (!handle_if_logic(ef, result != 0)) + return free(last), RETURN_FAILURE; + return free(last), RETURN_SUCCESS; } diff --git a/src/shell.c b/src/shell.c index 92cb6a3..d50fe48 100644 --- a/src/shell.c +++ b/src/shell.c @@ -20,7 +20,6 @@ #include "repl.h" #include "shell.h" #include "u_str.h" -#include "visitor.h" __attribute__((unused)) static @@ -54,7 +53,7 @@ void write_prompt(int is_a_tty) static bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx) { - char *tmp_buff = NULL; + char *tmp_buff = nullptr; size_t buffer_len; buff->sz = 0; @@ -78,7 +77,7 @@ bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx) static int shell_loop(int is_a_tty, exec_ctx_t *exec_ctx) { - buff_t buff = { .str = NULL, 0, .cap = BUFF_INIT_SZ }; + buff_t buff = { .str = nullptr, 0, .cap = BUFF_INIT_SZ }; init_shell_repl(exec_ctx); while (true) { @@ -86,7 +85,6 @@ int shell_loop(int is_a_tty, exec_ctx_t *exec_ctx) if (!change_shell_command(&buff, exec_ctx)) return exec_ctx->history->last_exit_code; } - free(exec_ctx->history_command); return free(buff.str), exec_ctx->history->last_exit_code; } @@ -96,10 +94,10 @@ his_command_t *init_cmd_history(void) his_command_t *cmd_history = malloc(sizeof(his_command_t) * 100); if (cmd_history == NULL) - return NULL; + return nullptr; for (int i = 0; i != 100; i++){ - cmd_history[i].arg = NULL; - cmd_history[i].command = NULL; + cmd_history[i].arg = nullptr; + cmd_history[i].command = nullptr; cmd_history[i].id = i; } cmd_history->sz = 0; @@ -121,20 +119,19 @@ bool error_in_init(exec_ctx_t *exec_ctx) return false; } -#include int shell(char **env_ptr) { alias_t alias = init_alias(); env_t env = parse_env(env_ptr); - history_t history = { .cmd_history = NULL, .last_exit_code = 0, - .last_chdir = NULL}; + 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, .history = &history, .history_command = cmd_history, .alias = &alias}; int shell_result; - if (error_in_init(&exec_ctx) == true) + if (error_in_init(&exec_ctx)) return RETURN_FAILURE; U_DEBUG_CALL(debug_env_entries, &env); shell_result = shell_loop(isatty(STDIN_FILENO), &exec_ctx); From bc40cf75980bb19a37c3f52e9775fc9c7fffc9fa Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 21:04:09 +0200 Subject: [PATCH 07/46] Refactor loop --- src/builtins/get_loop_cmd.c | 50 ++++++++++++++++--------------------- src/builtins/loop.c | 29 +++++++++++---------- src/loop.h | 2 +- 3 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/builtins/get_loop_cmd.c b/src/builtins/get_loop_cmd.c index 83b4f32..b40c3ce 100644 --- a/src/builtins/get_loop_cmd.c +++ b/src/builtins/get_loop_cmd.c @@ -5,36 +5,30 @@ ** get_loop_cmd */ +#include #include #include #include #include #include -#include -#include #include #include -#include +#include -#include "ast.h" -#include "builtins.h" #include "common.h" -#include "exec.h" -#include "redirects.h" -#include "u_str.h" -#include "u_mem.h" #include "loop.h" -#include "local.h" +#include "u_mem.h" +#include "u_str.h" static usr_cmd_t *buffers_realloc(usr_cmd_t *usr) { - char **new_buffers = u_realloc(usr->cmds, sizeof + char **new_buffers = (char **)u_realloc((void *)usr->cmds, sizeof *usr->cmds * usr->sz, sizeof *usr->cmds * (usr->cap << 1)); - if (new_buffers == NULL) - return NULL; + if ((void *)new_buffers == NULL) + return nullptr; usr->cmds = new_buffers; usr->cap <<= 1; return usr; @@ -43,7 +37,7 @@ usr_cmd_t *buffers_realloc(usr_cmd_t *usr) static usr_cmd_t *increase_buffers(usr_cmd_t *usr, size_t *buffer_len) { - usr->cmds[usr->sz] = NULL; + 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'; @@ -52,27 +46,27 @@ usr_cmd_t *increase_buffers(usr_cmd_t *usr, size_t *buffer_len) } static -usr_cmd_t *handle_end(usr_cmd_t *us, char prompt[]) +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])){ + 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 = NULL; + us->cmds = nullptr; exit(RETURN_FAILURE); - return NULL; + return nullptr; } free(us->cmds[us->sz]); - us->cmds[us->sz] = NULL; + us->cmds[us->sz] = nullptr; return us; } static -usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char prompt[], size_t *bf_len) +usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char const *prompt, size_t *bf_len) { if (isatty(STDIN_FILENO)) printf("%s? ", prompt); - usr->cmds[usr->sz] = NULL; + 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'; @@ -80,23 +74,23 @@ usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char prompt[], size_t *bf_len) return usr; } -usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char prompt[]) +usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char const *prompt) { size_t buffer_len; if (usr_cmd == NULL) - return NULL; - usr_cmd->cmds = malloc(sizeof(char *) * usr_cmd->cap); - if (usr_cmd->cmds == NULL) - return 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(usr_cmd, prompt, &buffer_len); - while (strcmp("end", usr_cmd->cmds[usr_cmd->sz - 1])){ + while (strcmp("end", usr_cmd->cmds[usr_cmd->sz - 1]) != 0){ if (isatty(STDIN_FILENO)) printf("%s? ", prompt); if (usr_cmd->sz >= usr_cmd->cap) usr_cmd = buffers_realloc(usr_cmd); if (usr_cmd == NULL) - return NULL; + return nullptr; increase_buffers(usr_cmd, &buffer_len); } usr_cmd = handle_end(usr_cmd, prompt); diff --git a/src/builtins/loop.c b/src/builtins/loop.c index 41849b5..e3baa3b 100644 --- a/src/builtins/loop.c +++ b/src/builtins/loop.c @@ -4,26 +4,25 @@ ** File description: ** foreach */ + +#include +#include #include #include #include #include #include -#include -#include #include #include -#include +#include #include "ast.h" #include "builtins.h" #include "common.h" #include "exec.h" -#include "redirects.h" -#include "u_str.h" -#include "u_mem.h" -#include "loop.h" #include "local.h" +#include "loop.h" +#include "u_str.h" void exit_child(int sig __attribute__((unused))) { @@ -31,7 +30,7 @@ void exit_child(int sig __attribute__((unused))) } static -bool checking_for_error(ef_t *ef, char **args) +bool checking_for_error(char **args) { if (my_array_len(args) < 3) return (WRITE_CONST(STDERR_FILENO, "foreach: Too few arguments.\n"), @@ -42,7 +41,7 @@ bool checking_for_error(ef_t *ef, char **args) } static -bool checking_while_error(ef_t *ef, char **args) +bool checking_while_error(char **args) { if (my_array_len(args) < 2) return (WRITE_CONST(STDERR_FILENO, "while: Too few arguments.\n"), @@ -69,7 +68,7 @@ int foreach_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmds) int status = 0; char **save_cmds = arraydup(usr_cmds->cmds); - if (save_cmds == NULL) + if ((void *)save_cmds == NULL) exit(84); for (int i = 2; args[i]; i++){ if (!set_local(ef->exec_ctx->local, args[1], args[i])) @@ -88,7 +87,7 @@ int while_loop(ef_t *ef, usr_cmd_t *usr_cmds) int status = 0; char **save_cmds = arraydup(usr_cmds->cmds); - if (save_cmds == NULL) + if ((void *)save_cmds == NULL) exit(84); while (true){ status = do_a_lap(ef, usr_cmds->cmds); @@ -100,7 +99,7 @@ int while_loop(ef_t *ef, usr_cmd_t *usr_cmds) } static -int choose_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmd, char prompt[]) +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); @@ -108,7 +107,7 @@ int choose_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmd, char prompt[]) } static -void launch_loop(ef_t *ef, char **args, char prompt[]) +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)); @@ -134,7 +133,7 @@ int builtins_foreach(ef_t *ef, char **args) int status = 0; pid_t pid; - if (checking_for_error(ef, args)) + if (checking_for_error(args)) return RETURN_FAILURE; pid = fork(); if (pid == 0) @@ -152,7 +151,7 @@ int builtins_while(ef_t *ef, char **args) int status = 0; pid_t pid; - if (checking_while_error(ef, args)) + if (checking_while_error(args)) return RETURN_FAILURE; pid = fork(); if (pid == 0) diff --git a/src/loop.h b/src/loop.h index b8f8544..84c72f0 100644 --- a/src/loop.h +++ b/src/loop.h @@ -16,5 +16,5 @@ typedef struct { char **cmds; } usr_cmd_t; -usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char prompt[]); +usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char const *prompt); #endif /* LOOP_H */ From 1c9d1e82d866b3909cf527269a5016908b88b926 Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 21:18:15 +0200 Subject: [PATCH 08/46] Refactor while --- src/builtins/expr/expr_main.c | 6 +++--- src/builtins/local.c | 32 +++++++++++++++----------------- src/builtins/loop.c | 25 +++++++++++++++++-------- ulib/str/arraydup.c | 16 ++++++++-------- 4 files changed, 43 insertions(+), 36 deletions(-) diff --git a/src/builtins/expr/expr_main.c b/src/builtins/expr/expr_main.c index 1f032cb..4c913a1 100644 --- a/src/builtins/expr/expr_main.c +++ b/src/builtins/expr/expr_main.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "common.h" @@ -19,14 +18,15 @@ int builtins_expr(ef_t *ef[[gnu::unused]], char **args) expr_state_t state; expr_val_t ret; - for (; args[argc] != NULL; argc++); + for (; args[argc] != nullptr; argc++); if (argc < 2) return fprintf(stderr, "%s: missing operand\n", 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) + 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); diff --git a/src/builtins/local.c b/src/builtins/local.c index 29b7d1c..46e7a5f 100644 --- a/src/builtins/local.c +++ b/src/builtins/local.c @@ -6,16 +6,14 @@ */ #include -#include -#include -#include #include +#include +#include +#include #include "common.h" -#include "env.h" -#include "exec.h" -#include "u_str.h" #include "u_mem.h" +#include "u_str.h" bool check_local_var(char *var, char *func_name) { @@ -33,14 +31,14 @@ 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] == NULL) + 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 NULL; + return nullptr; } local_t create_local(void) @@ -48,9 +46,9 @@ 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 == NULL) - return (local_t){.sz = 0, .cap = 2, .local_var = NULL}; - local.local_var[local.sz] = NULL; + 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; } @@ -58,7 +56,7 @@ local_t create_local(void) static bool ensure_local_capacity(local_t *local) { - char **new_ptr = NULL; + char **new_ptr = nullptr; if (local->sz < local->cap) return true; @@ -74,17 +72,17 @@ bool ensure_local_capacity(local_t *local) bool set_local(local_t *local, char *var, char *value) { - char *new_loc = NULL; + char *new_loc = nullptr; size_t key_len = u_strlen(var); size_t value_len = u_strlen(value); - if (get_local_value(local, var) != NULL) + 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 == NULL) + if (new_loc == nullptr) return false; u_bzero(new_loc, key_len + value_len + 2); u_strcpy(new_loc, var); @@ -92,7 +90,7 @@ bool set_local(local_t *local, char *var, char *value) 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] = NULL; + local->local_var[local->sz] = nullptr; return true; } @@ -110,7 +108,7 @@ 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] == NULL) + if (local->local_var[i] == nullptr) continue; if (u_strcspn(local->local_var[i], '\t') != key_len) continue; diff --git a/src/builtins/loop.c b/src/builtins/loop.c index e3baa3b..e945852 100644 --- a/src/builtins/loop.c +++ b/src/builtins/loop.c @@ -19,12 +19,13 @@ #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 __attribute__((unused))) +void exit_child(int sig[[gnu::unused]]) { _exit(sig); } @@ -68,7 +69,7 @@ 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 == NULL) + 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])) @@ -82,17 +83,25 @@ int foreach_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmds) } static -int while_loop(ef_t *ef, usr_cmd_t *usr_cmds) +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 == NULL) + if ((void *)save_cmds == nullptr) exit(84); - while (true){ + 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; @@ -103,7 +112,7 @@ 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); + return while_loop(ef, usr_cmd, args); } static @@ -113,14 +122,14 @@ void launch_loop(ef_t *ef, char **args, char const *prompt) usr_cmd_t *usr_cmds = malloc(sizeof(usr_cmd_t)); ef->exec_ctx->local->in_a_loop = true; - if (usr_cmds == NULL) + 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(usr_cmds, prompt); - if (usr_cmds == NULL) + if (usr_cmds == nullptr) exit(84); status = choose_loop(ef, args, usr_cmds, prompt); free_array(usr_cmds->cmds); diff --git a/ulib/str/arraydup.c b/ulib/str/arraydup.c index 2bf8d11..c32dda4 100644 --- a/ulib/str/arraydup.c +++ b/ulib/str/arraydup.c @@ -9,16 +9,16 @@ char **arraydup(char **array) { - char **dup_array = NULL; + char **dup_array = nullptr; int i = 0; - if (array == NULL) - return NULL; - dup_array = malloc(sizeof(char *) * (my_array_len(array) + 1)); - if (dup_array == NULL) - return NULL; - for (; array[i] != NULL; i++) + if (array == nullptr) + return nullptr; + dup_array = (char **)malloc(sizeof(char *) * (my_array_len(array) + 1)); + if (dup_array == nullptr) + return nullptr; + for (; array[i] != nullptr; i++) dup_array[i] = u_strdup(array[i]); - dup_array[i] = NULL; + dup_array[i] = nullptr; return dup_array; } From 77f5f29225e216a8653c6ea6356ddb0eb1205f65 Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 21:19:28 +0200 Subject: [PATCH 09/46] Add backticks tests --- validation_tests.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/validation_tests.py b/validation_tests.py index d0c3b83..0856ce8 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -205,20 +205,14 @@ TESTS = [ depends_on=() ), - ##Test( - ## key="BACKTICKS", - ## name="backticks", - ## cmds=[ - ## "echo `ls`\n", - ## "echo `ls`l\n", - ## "echo l`ls`\n", - ## "echo ``\n", - ## "`ls`\n", - ## "``\n", - ## "echo `ls\n", - ## "echo ls`\n", - ## "`\n", - ## ], - ## depends_on=() - ##), + Test( + key="BACKTICKS", + name="backticks", + cmds=[ + "echo `ls`\n", + "echo `ls\n", + "echo ls`\n", + ], + depends_on=() + ), ] From 7c4f2afef2dd929c435f87e963fd46b089bc2b0f Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 21:27:55 +0200 Subject: [PATCH 10/46] Fix cs --- src/builtins.h | 13 +++++++++++++ src/builtins/if.c | 12 ------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/builtins.h b/src/builtins.h index 78e00a3..9e8e9ef 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -9,6 +9,19 @@ #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; diff --git a/src/builtins/if.c b/src/builtins/if.c index 877c94d..48f9dc7 100644 --- a/src/builtins/if.c +++ b/src/builtins/if.c @@ -16,18 +16,6 @@ #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; - static int get_argc(char **args) { From c04b2fb9d2f5f7a7b0f2817e4dbeb5923ec69751 Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 21:48:46 +0200 Subject: [PATCH 11/46] Add if tests --- src/builtins/if.c | 10 ++++++---- validation_tests.py | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/builtins/if.c b/src/builtins/if.c index 48f9dc7..a53fb58 100644 --- a/src/builtins/if.c +++ b/src/builtins/if.c @@ -21,7 +21,7 @@ int get_argc(char **args) { int i = 0; - for (; args[i]; i++); + for (; args[i] != nullptr; i++); return i; } @@ -118,12 +118,14 @@ void exec_block(cmd_block_t *blk, ef_t *ef) } static -bool handle_if_logic(ef_t *ef, bool cond) +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(&ctx, &then_blk, &else_blk)) @@ -147,7 +149,7 @@ int builtins_if(ef_t *ef, char **args) 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; + return WRITE_CONST(STDERR_FILENO, "if: Empty if.\n"), RETURN_FAILURE; last = strdup(args[get_argc(args) - 1]); if (!last) return RETURN_FAILURE; @@ -156,7 +158,7 @@ int builtins_if(ef_t *ef, char **args) U_DEBUG("If expr result [%d]\n", result); if (result == -1) return free(last), RETURN_FAILURE; - if (!handle_if_logic(ef, result != 0)) + if (!handle_if_logic(ef, result != 0, last)) return free(last), RETURN_FAILURE; return free(last), RETURN_SUCCESS; } diff --git a/validation_tests.py b/validation_tests.py index 0856ce8..e8c2b22 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -215,4 +215,18 @@ TESTS = [ ], depends_on=() ), + + Test( + key="IF", + name="if", + cmds=[ + "if 1 ls\n", + "if 0 ls\n", + "if 1 then\necho YES\nelse\necho NO\nendif\n", + "if 0 then\necho YES\nelse\necho NO\nendif\n", + "if\n", + "if 0\n", + ], + depends_on=() + ), ] From 2de3514d0b1a299cb7aa67387f36a7c5040d2cc3 Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 21:54:15 +0200 Subject: [PATCH 12/46] Remove useless file Remove useless file --- iftest.sh | 5 ----- out.txt | 3 --- 2 files changed, 8 deletions(-) delete mode 100644 iftest.sh delete mode 100644 out.txt diff --git a/iftest.sh b/iftest.sh deleted file mode 100644 index e3ffc45..0000000 --- a/iftest.sh +++ /dev/null @@ -1,5 +0,0 @@ -if ls - echo YES -else - echo NO -endif diff --git a/out.txt b/out.txt deleted file mode 100644 index 45f0b6a..0000000 --- a/out.txt +++ /dev/null @@ -1,3 +0,0 @@ -plop -again -again From 505390f74efae0b99c3d47f0acfe33134da28748 Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 21:58:13 +0200 Subject: [PATCH 13/46] Update README --- README.md | 19 ++++++------------- src/exec.c | 6 +++--- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 107eb2a..47003f3 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,9 @@ - [x] redirections - [ ] line editing (move, del, multi-line) - [ ] input shortcut (^A,^E,^R,^V,^F,^B,...) -- [ ] color highlighting in input - [ ] foreground/background jobs (`&`), (btln `fg`, `bg`, `jobs`) -- [ ] while/for/foreach loops -- [ ] if / cases +- [x] while/foreach loops +- [x] if - [x] `||`/`&&` - [ ] configuration file - [x] script with shebangs @@ -40,19 +39,13 @@ - [ ] `-e` exit on failure - [ ] `-n` (dry run mode) - [ ] `-h` help (open man?) -- [ ] autocompletion of commands - [x] globbing -- [ ] var interpreter -- [ ] inhibitor -- [ ] magic quotes -- [ ] parenthesis (sub-commands) -- [ ] direnv/wakatime integration +- [x] var interpreter +- [x] inhibitor +- [x] magic quotes +- [x] parenthesis - [x] command history (`history` btln) -- [ ] arithmetric expansion (`$(( x + 1 ))`) -- [ ] brace expansion: `{a,b,c}` and `{1..10}` - [x] heredocs - [ ] functions (`:() { :|:& }`) - [ ] special env vars: `$?`, `$$`, ... - [ ] git integration (branch) -- [ ] `x`, `e`, `o` & pipefail modes -- [ ] file inquiry operators (`-d`, `f`, ...) diff --git a/src/exec.c b/src/exec.c index f4dcc1a..38ca266 100644 --- a/src/exec.c +++ b/src/exec.c @@ -75,7 +75,7 @@ char **parse_args(ef_t *ef, ast_t *node) * DEFAULT_ARGS_CAP), .sz = 0, .cap = DEFAULT_ARGS_CAP }; if (!args.args) - return NULL; + 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; @@ -83,8 +83,8 @@ char **parse_args(ef_t *ef, ast_t *node) return free((void *)args.args), NULL; } if (!ensure_args_capacity(&args)) - return NULL; - args.args[args.sz] = NULL; + return nullptr; + args.args[args.sz] = nullptr; return args.args; } From fe892e6c615dcb3b1cbfad2cebb33734c0f0f934 Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 21:59:51 +0200 Subject: [PATCH 14/46] Change globbing file name to args.c --- src/{globbing.c => args.c} | 4 ++-- src/{globbing.h => args.h} | 0 src/exec.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/{globbing.c => args.c} (94%) rename src/{globbing.h => args.h} (100%) diff --git a/src/globbing.c b/src/args.c similarity index 94% rename from src/globbing.c rename to src/args.c index ba1774c..679d54a 100644 --- a/src/globbing.c +++ b/src/args.c @@ -12,8 +12,8 @@ #include #include +#include "args.h" #include "exec.h" -#include "globbing.h" bool check_glob_result(int val, char *bin_name) { @@ -31,7 +31,7 @@ bool process_globbing(char *pattern, args_t *args, size_t *toks_i) int glob_result; char *vl; - glob_result = glob(pattern, GLOB_ERR, NULL, &globs); + 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++) { diff --git a/src/globbing.h b/src/args.h similarity index 100% rename from src/globbing.h rename to src/args.h diff --git a/src/exec.c b/src/exec.c index 38ca266..09cba4b 100644 --- a/src/exec.c +++ b/src/exec.c @@ -13,13 +13,13 @@ #include #include +#include "args.h" #include "ast.h" #include "builtins.h" #include "common.h" #include "debug.h" #include "env.h" #include "exec.h" -#include "globbing.h" #include "path.h" #include "repl.h" #include "u_mem.h" From 5f2645c6af74cfe4b33a65e11c017bee7133a4bc Mon Sep 17 00:00:00 2001 From: savalet Date: Sat, 3 May 2025 22:42:48 +0200 Subject: [PATCH 15/46] Add tester in makefile --- Makefile | 3 +-- validator.py | 17 ++++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 410cada..d01de32 100644 --- a/Makefile +++ b/Makefile @@ -81,8 +81,7 @@ all: $(NAME_release) .PHONY: tests_run tests_run: $(NAME_test) - - find fixtures -name "*.sh" | xargs -i \ - sh -c 'cat {} | env -i PATH="$(dir $(shell which ls))" ./$^' + @ - python3 validator.py ./$(NAME_test) .PHONY: cov cov: tests_run diff --git a/validator.py b/validator.py index c4cb129..ef40071 100755 --- a/validator.py +++ b/validator.py @@ -66,7 +66,7 @@ class Test: key: str, name: str, cmds: list[str], - depends_on: tuple[str, ...] = () + depends_on: tuple[str, ...] = (), ): self.key = key self.name = name @@ -74,8 +74,8 @@ class Test: self.depends_on = depends_on self.has_run = False - def _run_each_cmd(self, cmd: str): - result_42sh = run_shell(["./42sh"], cmd) + def _run_each_cmd(self, cmd: str, tested_bin): + result_42sh = run_shell([tested_bin], cmd) result_tcsh = run_shell(["tcsh"], cmd) if result_42sh.exit_code == 84 and result_tcsh.exit_code != 0: @@ -88,7 +88,7 @@ class Test: print("\033[31m.\033[0m", end='') # ]] return cmd, result_42sh, result_tcsh - def run(self, test_map) -> bool: + def run(self, test_map, tested_bin) -> bool: if self.has_run: return True @@ -104,7 +104,7 @@ class Test: continue if not dep.has_run: - success &= dep.run(test_map) + success &= dep.run(test_map, tested_bin) if not success: return False @@ -112,7 +112,7 @@ class Test: failures = [] for cmd in self.cmds: - if (failure := self._run_each_cmd(cmd)) is not None: + if (failure := self._run_each_cmd(cmd, tested_bin)) is not None: failures.append(failure) if not failures: print(" \033[32mOK\033[0m") # ]] @@ -130,7 +130,10 @@ def main(): success = True for test in TESTS: - success &= test.run(test_map=test_map) + success &= test.run( + test_map=test_map, + tested_bin=sys.argv[1] if len(sys.argv) > 1 else "./42sh" + ) return not success From 7d185e2954f9c63f5b8989fbde387f6070f6dfd1 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 16:04:52 +0200 Subject: [PATCH 16/46] Add eq and neq to expr --- src/builtins/expr/expr_applicators.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/builtins/expr/expr_applicators.c b/src/builtins/expr/expr_applicators.c index 9f48e6f..6956074 100644 --- a/src/builtins/expr/expr_applicators.c +++ b/src/builtins/expr/expr_applicators.c @@ -99,6 +99,30 @@ expr_val_t apply_gt(expr_val_t *left, expr_val_t *right) 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 }, @@ -106,6 +130,8 @@ const expr_op_precedence_t OPERATOR_PRECEDENCE[] = { { .name = "/", .prec = 3, apply_div }, { .name = "<", .prec = 1, apply_lt }, { .name = ">", .prec = 1, apply_gt }, + { .name = "==", .prec = 1, apply_eq }, + { .name = "!=", .prec = 1, apply_neq }, }; const size_t OPERATOR_PRECEDENCE_COUNT = COUNT_OF(OPERATOR_PRECEDENCE); From 60869b1526b4a574953991ffb54f6254ab6b4130 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 16:18:37 +0200 Subject: [PATCH 17/46] Refactor history --- src/parse_history.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/parse_history.c b/src/parse_history.c index 16e5bae..6fde9d7 100644 --- a/src/parse_history.c +++ b/src/parse_history.c @@ -4,20 +4,16 @@ ** File description: ** his for history */ + #include -#include #include #include -#include #include +#include -#include "utils.h" -#include "common.h" -#include "env.h" -#include "exec.h" -#include "u_mem.h" -#include "u_str.h" #include "history.h" +#include "u_str.h" +#include "utils.h" const parsing_history_t tab_fnct[] = { {"!!", &his_last_command}, From 93e74e6c9c8f1b2dff37309e9d647a67cd532431 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 16:40:56 +0200 Subject: [PATCH 18/46] Add new prompt handling --- src/common.h | 1 + src/readline.c | 9 +++++---- src/readline.h | 3 ++- src/repl.c | 25 +++++++++++++++++++++---- src/repl.h | 3 ++- src/shell.c | 8 ++++---- src/shell.h | 3 --- 7 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/common.h b/src/common.h index a515665..8b4b7e9 100644 --- a/src/common.h +++ b/src/common.h @@ -8,6 +8,7 @@ #ifndef COMMON_H #define COMMON_H #include "exec.h" + #define IF_PROMPT "if? " enum { diff --git a/src/readline.c b/src/readline.c index 9ebef6d..02c10ea 100644 --- a/src/readline.c +++ b/src/readline.c @@ -82,9 +82,10 @@ bool append_null_terminator(buff_t *buff) } static -int8_t handle_line_buff(buff_t *buff, char *read_buff, ssize_t read_size) +int8_t handle_line_buff(exec_ctx_t *exec_ctx, buff_t *buff, char *read_buff, + ssize_t read_size) { - if (handle_keys(buff, read_buff)) + if (handle_keys(exec_ctx, buff, read_buff)) return RETURN_SUCCESS; if (isatty(STDIN_FILENO) && str_printable(read_buff, read_size)) write(STDOUT_FILENO, read_buff, read_size); @@ -96,7 +97,7 @@ int8_t handle_line_buff(buff_t *buff, char *read_buff, ssize_t read_size) return -1; } -bool readline(buff_t *buff) +bool readline(exec_ctx_t *exec_ctx, buff_t *buff) { char read_buff[2] = ""; ssize_t read_size = 0; @@ -110,7 +111,7 @@ bool readline(buff_t *buff) return false; if (read_size == 0) return true; - if (handle_line_buff(buff, read_buff, read_size) > -1) + if (handle_line_buff(exec_ctx, buff, read_buff, read_size) > -1) return true; } return append_null_terminator(buff); diff --git a/src/readline.h b/src/readline.h index 67d6510..940642f 100644 --- a/src/readline.h +++ b/src/readline.h @@ -10,7 +10,8 @@ #define BUFF_INIT_SZ 16 #include + #include "exec.h" #include "u_str.h" -bool readline(buff_t *buff); +bool readline(exec_ctx_t *exec_ctx, buff_t *buff); #endif /* READLINE */ diff --git a/src/repl.c b/src/repl.c index 217c76f..5186206 100644 --- a/src/repl.c +++ b/src/repl.c @@ -6,16 +6,33 @@ */ #include +#include #include #include #include "exec.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"); + + if (ps1 == nullptr) { + printf(BLUE "┌─[" GREEN "%s" BLUE "] " RESET "-" BLUE " [" RESET "%s" + BLUE "]\n└─[" PURPLE "$" BLUE "] " RESET, + get_env_value(env_ptr, "USER"), + get_env_value(env_ptr, "PWD")); + } else + printf("%s", ps1); +} void init_shell_repl(exec_ctx_t *exec_ctx) { struct termios repl_settings; + setvbuf(stdout, nullptr, _IONBF, 0); signal(SIGINT, SIG_IGN); exec_ctx->is_running = true; if (isatty(STDIN_FILENO)) { @@ -33,20 +50,20 @@ void restore_term_flags(exec_ctx_t *exec_ctx) } static -void ignore_sigint(void) +void ignore_sigint(exec_ctx_t *exec_ctx) { WRITE_CONST(STDIN_FILENO, "\n"); - WRITE_CONST(STDOUT_FILENO, SHELL_PROMPT); + print_shell_prompt(exec_ctx); } -bool handle_keys(buff_t *buff, char *read_buff) +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(); + ignore_sigint(exec_ctx); return false; default: return false; diff --git a/src/repl.h b/src/repl.h index 25f4868..d046ee7 100644 --- a/src/repl.h +++ b/src/repl.h @@ -12,5 +12,6 @@ void init_shell_repl(exec_ctx_t *exec_ctx); void restore_term_flags(exec_ctx_t *exec_ctx); -bool handle_keys(buff_t *buff, char *read_buff); +bool handle_keys(exec_ctx_t *exec_ctx, buff_t *buff, char const *read_buff); +void print_shell_prompt(exec_ctx_t *exec_ctx); #endif /* REPL_H */ diff --git a/src/shell.c b/src/shell.c index d50fe48..54ef44a 100644 --- a/src/shell.c +++ b/src/shell.c @@ -44,10 +44,10 @@ void check_basic_error(char const *buffer) } static -void write_prompt(int is_a_tty) +void write_prompt(int is_a_tty, exec_ctx_t *exec_ctx) { if (is_a_tty) - WRITE_CONST(STDOUT_FILENO, SHELL_PROMPT); + print_shell_prompt(exec_ctx); } static @@ -57,7 +57,7 @@ bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx) size_t buffer_len; buff->sz = 0; - if (!readline(buff)) + if (!readline(exec_ctx, buff)) return false; if (!buff->sz) return false; @@ -81,7 +81,7 @@ int shell_loop(int is_a_tty, exec_ctx_t *exec_ctx) init_shell_repl(exec_ctx); while (true) { - write_prompt(is_a_tty); + write_prompt(is_a_tty, exec_ctx); if (!change_shell_command(&buff, exec_ctx)) return exec_ctx->history->last_exit_code; } diff --git a/src/shell.h b/src/shell.h index ec0f497..9aea593 100644 --- a/src/shell.h +++ b/src/shell.h @@ -7,9 +7,6 @@ #ifndef SHELL_H #define SHELL_H - #include "vt100_esc_codes.h" - - #define SHELL_PROMPT RED "|> " RESET typedef struct { char **cmd_history; From 70156fd01291dbff2e41d8c7160752cd8fc63f05 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 16:40:59 +0200 Subject: [PATCH 19/46] Add expr tests --- validation_tests.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/validation_tests.py b/validation_tests.py index e8c2b22..6e1bd35 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -229,4 +229,19 @@ TESTS = [ ], depends_on=() ), + + Test( + key="EXPR", + name="expr builtin command", + cmds=[ + "expr 1 + 2", + "expr 4 - 2", + "expr 3 \\* 5", + "expr 5 = 5", + "expr 5 \\< 10", + "expr 5 \\> 3", + "expr\n", + ], + depends_on=("ARGS",) + ), ] From cb16839a10c1a0ee500101781e05caa94c4b5fbe Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 16:41:15 +0200 Subject: [PATCH 20/46] Add = in expr --- src/builtins/expr/expr_applicators.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/builtins/expr/expr_applicators.c b/src/builtins/expr/expr_applicators.c index 6956074..1137d77 100644 --- a/src/builtins/expr/expr_applicators.c +++ b/src/builtins/expr/expr_applicators.c @@ -130,6 +130,7 @@ const expr_op_precedence_t OPERATOR_PRECEDENCE[] = { { .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 }, }; From 73f4499e0e5c24a13d6e95776292721eeee72ecb Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 16:41:28 +0200 Subject: [PATCH 21/46] Add backslash as a token --- src/ast.h | 9 +++++---- src/ast/ast.c | 4 ++-- src/ast/tokeniser.c | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ast.h b/src/ast.h index 535f159..b0ca08b 100644 --- a/src/ast.h +++ b/src/ast.h @@ -37,10 +37,11 @@ typedef enum size_t { T_AT = 1 << 15, // < T_WHILE = 1 << 16, // while T_STAR = 1 << 18, // * - T_NEWLINE = 1 << 19, // \n - T_EOF = 1 << 20, // \0 - T_ARG = 1 << 21, - T_INVALID = 1 << 22 + T_BACKSLASH = 1 << 19, + T_NEWLINE = 1 << 20, // \n + T_EOF = 1 << 21, // \0 + T_ARG = 1 << 22, + T_INVALID = 1 << 23 } token_type_t; typedef enum { diff --git a/src/ast/ast.c b/src/ast/ast.c index 44c6cf5..f0fa0ac 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -18,9 +18,9 @@ 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) + if (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE)) return node; - if (*ctx->act_tok.str == '\\') { + if (ctx->act_tok.type == T_BACKSLASH) { ctx->act_tok = get_next_token(ctx); if (ctx->act_tok.type == T_EOF) return node; diff --git a/src/ast/tokeniser.c b/src/ast/tokeniser.c index cf18967..9d8660f 100644 --- a/src/ast/tokeniser.c +++ b/src/ast/tokeniser.c @@ -28,6 +28,7 @@ const tokens_list_t TOKENS_LIST[] = { { 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_STAR, "*", 1, "T_STAR"}, { T_EOF, "\0", 1, "T_EOF" } From 859fc8b2e3b65e0148061da0e96260c9ec8395ee Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 16:56:19 +0200 Subject: [PATCH 22/46] Fix expr --- src/builtins/expr/expr_main.c | 3 ++- validation_tests.py | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/builtins/expr/expr_main.c b/src/builtins/expr/expr_main.c index 4c913a1..785905b 100644 --- a/src/builtins/expr/expr_main.c +++ b/src/builtins/expr/expr_main.c @@ -20,7 +20,8 @@ int builtins_expr(ef_t *ef[[gnu::unused]], char **args) for (; args[argc] != nullptr; argc++); if (argc < 2) - return fprintf(stderr, "%s: missing operand\n", args[0]), -1; + 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) diff --git a/validation_tests.py b/validation_tests.py index 6e1bd35..b6a002c 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -236,11 +236,10 @@ TESTS = [ cmds=[ "expr 1 + 2", "expr 4 - 2", - "expr 3 \\* 5", - "expr 5 = 5", - "expr 5 \\< 10", - "expr 5 \\> 3", - "expr\n", + #"expr 3 \\* 5", + #"expr 5 = 5", + #"expr 5 \\< 10", + #"expr 5 \\> 3", ], depends_on=("ARGS",) ), From 61d57f99b0e0b36a46912e19f1249da48c8c69ce Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 16:56:24 +0200 Subject: [PATCH 23/46] Add custom prompt --- src/repl.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/repl.c b/src/repl.c index 5186206..d741d73 100644 --- a/src/repl.c +++ b/src/repl.c @@ -18,12 +18,19 @@ 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) { - printf(BLUE "┌─[" GREEN "%s" BLUE "] " RESET "-" BLUE " [" RESET "%s" - BLUE "]\n└─[" PURPLE "$" BLUE "] " RESET, + if (gethostname(hostname, 64)) + return; + printf(BLUE "┌─[" 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"), - get_env_value(env_ptr, "PWD")); + hostname, + get_env_value(env_ptr, "PWD"), + exec_ctx->history_command->sz); } else printf("%s", ps1); } From 370f43f4d11d73140eb40fcd42d24dd65c7a582c Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 17:03:11 +0200 Subject: [PATCH 24/46] Fix gethostname error check --- src/repl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/repl.c b/src/repl.c index d741d73..f5b0d09 100644 --- a/src/repl.c +++ b/src/repl.c @@ -21,7 +21,7 @@ void print_shell_prompt(exec_ctx_t *exec_ctx) char hostname[64]; if (ps1 == nullptr) { - if (gethostname(hostname, 64)) + if (gethostname(hostname, 64) < 0) return; printf(BLUE "┌─[" GREEN "%s" RESET "@" CYAN "%s" BLUE "] " RESET "-" BLUE " [" RESET "%s" BLUE From 42bce47cae74f52b0d2c291eae0d314777aebdf3 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 17:06:19 +0200 Subject: [PATCH 25/46] Fix backslash --- src/args.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/args.c b/src/args.c index 679d54a..b25b0b4 100644 --- a/src/args.c +++ b/src/args.c @@ -58,8 +58,6 @@ bool process_args(ast_t *node, args_t *args, size_t *toks_i, ef_t *ef) handle_var_case(node, ef->exec_ctx, toks_i, args); if (args->args[args->sz] == NULL) return false; - if (strchr(tok.str, '\\') != NULL) - args->args[args->sz] = tok.str; args->sz++; return true; } From e4a6c7c01b71155b5757456487d881f52bd23e31 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 18:23:38 +0200 Subject: [PATCH 26/46] Fix C-F9 false positive in repl --- src/common.h | 1 + src/repl.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/common.h b/src/common.h index 8b4b7e9..8b7c3de 100644 --- a/src/common.h +++ b/src/common.h @@ -9,6 +9,7 @@ #define COMMON_H #include "exec.h" + #define PROMPT_HEADER "┌─[" #define IF_PROMPT "if? " enum { diff --git a/src/repl.c b/src/repl.c index f5b0d09..41081e1 100644 --- a/src/repl.c +++ b/src/repl.c @@ -10,10 +10,12 @@ #include #include +#include "common.h" #include "exec.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; @@ -23,7 +25,7 @@ void print_shell_prompt(exec_ctx_t *exec_ctx) if (ps1 == nullptr) { if (gethostname(hostname, 64) < 0) return; - printf(BLUE "┌─[" GREEN "%s" RESET "@" CYAN "%s" BLUE "] " + printf(BLUE PROMPT_HEADER GREEN "%s" RESET "@" CYAN "%s" BLUE "] " RESET "-" BLUE " [" RESET "%s" BLUE "] " RESET "-" BLUE " [" YELLOW "%d" BLUE "]\n└─[" PURPLE "$" BLUE "] " RESET, From 2d8c662e241bcdbb6f68465f830a5c71f6d2f4ae Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 18:40:42 +0200 Subject: [PATCH 27/46] Refactor yes --- src/builtins/yes.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/builtins/yes.c b/src/builtins/yes.c index 2790f4e..58e37ea 100644 --- a/src/builtins/yes.c +++ b/src/builtins/yes.c @@ -4,19 +4,20 @@ ** File description: ** yes */ -#include -#include -#include -#include + #include -#include #include +#include +#include +#include +#include +#include #include "builtins.h" #include "common.h" #include "exec.h" -#include "u_str.h" #include "u_mem.h" +#include "u_str.h" static int len_buffer(char **args) @@ -31,13 +32,13 @@ int len_buffer(char **args) static char *define_prompt(char **args) { - char *buffer = NULL; + char *buffer = nullptr; if (args[1] == NULL) return u_strdup("y\n"); buffer = malloc(sizeof(char) * (len_buffer(args) + 1)); if (buffer == NULL) - return NULL; + return nullptr; u_bzero(buffer, len_buffer(args) + 1); strcpy(buffer, args[1]); buffer[strlen(buffer)] = ' '; @@ -58,14 +59,12 @@ int builtins_yes(ef_t *ef, char **args) if (buffer == NULL) return RETURN_FAILURE; pid = fork(); - if (pid == 0){ - while (true){ - signal(SIGINT, exit_child); + if (pid == 0) { + signal(SIGINT, exit_child); + while (true) write(ef->out_fd, buffer, strlen(buffer)); - } - exit(RETURN_SUCCESS); } else - wait(NULL); + wait(nullptr); free(buffer); return RETURN_SUCCESS; } From e1fc6250d8fb476d76c101706e20293bb44acfea Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 18:40:58 +0200 Subject: [PATCH 28/46] Refactor history --- src/builtins/history.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtins/history.c b/src/builtins/history.c index ccc1754..a070bc6 100644 --- a/src/builtins/history.c +++ b/src/builtins/history.c @@ -6,8 +6,8 @@ */ #include + #include "common.h" -#include "env.h" #include "exec.h" int builtins_history(ef_t *ef, char **args __attribute__((unused))) From 2a785780a59046cd39c2c7e4816d5222b528aecc Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 18:41:31 +0200 Subject: [PATCH 29/46] Refactor repeat --- src/builtins/repeat.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/builtins/repeat.c b/src/builtins/repeat.c index ded5289..2affa22 100644 --- a/src/builtins/repeat.c +++ b/src/builtins/repeat.c @@ -4,13 +4,12 @@ ** File description: ** repeat */ -#include -#include -#include -#include + #include -#include #include +#include +#include +#include #include "builtins.h" #include "common.h" @@ -18,7 +17,7 @@ #include "u_str.h" static -bool checking_error(ef_t *ef, char **args, long *nb_loop) +bool checking_error(char **args, long *nb_loop) { char *end; @@ -39,7 +38,7 @@ int builtins_repeat(ef_t *ef, char **args) int status = 0; pid_t pid; - if (checking_error(ef, args, &nb_loop)) + if (checking_error(args, &nb_loop)) return RETURN_FAILURE; pid = fork(); if (pid == 0){ From 2f7b8cf28620099a4192400f424b66cc72cda2f0 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 18:47:49 +0200 Subject: [PATCH 30/46] Refactor history --- src/builtins/builtin_history.c | 59 ++++++++++++++++------------------ 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/src/builtins/builtin_history.c b/src/builtins/builtin_history.c index ddb27b7..e87cef2 100644 --- a/src/builtins/builtin_history.c +++ b/src/builtins/builtin_history.c @@ -5,10 +5,14 @@ ** builtin_history */ -#include +#include +#include #include +#include +#include #include "history.h" +#include "utils.h" /* **Il faut deux \0 parce que dans le gettokeniser @@ -26,31 +30,24 @@ ** il vas free le buffer */ -#include -#include "utils.h" -#include -#include -#include - static char *concat_cmd_arg(char *dest, char *src) { int l; int i; - char *r_value = NULL; + char *r_value = nullptr; if (!src) { r_value = u_strdup(dest); return r_value; - } else { - 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); - } + } + 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; } @@ -58,12 +55,12 @@ static char *concat_cmd_arg(char *dest, char *src) char *his_last_command(char *line, his_variable_t *his_variable, his_command_t *his_command) { - char *new_line = NULL; - char *new_str = NULL; + char *new_line = nullptr; + char *new_str = nullptr; if (his_command->sz == 0){ fprintf(stderr, "%d: Event not found.\n", his_command->sz); - return NULL; + return nullptr; } new_line = concat_cmd_arg(his_command[his_command->sz - 1].command, his_command[his_command->sz - 1].arg); @@ -76,7 +73,7 @@ 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 = NULL; + char *new_str = nullptr; for (int i = his_command->sz - 1; i > 0; i--) { if (his_command[i].command == NULL) { @@ -100,7 +97,7 @@ char *his_id_command(char *line, { int id = -1 + atoi(&line[his_variable->coord_variable + 1]); char *new_line; - char *new_str = NULL; + char *new_str = nullptr; if (id < 0 || id > 100 || his_command[id].command == NULL){ fprintf(stderr, "%d: Event not found.\n", id + 1); @@ -116,18 +113,18 @@ char *his_id_command(char *line, static char *get_last_word(char *str) { - char *last_word = NULL; + char *last_word = nullptr; int last_space = 0; int x = 0; if (!str) - return NULL; + return nullptr; while (str[x] != '\0') { if (isblank(str[x])) last_space = x + 1; x++; } - last_word = malloc(sizeof(char) * (x - last_space) + 1); + 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'; @@ -138,15 +135,15 @@ static char *get_last_word(char *str) char *his_last_word(char *line, his_variable_t *his_variable, his_command_t *his_command) { - char *new_line = NULL; - char *new_str = NULL; + 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 NULL; + return nullptr; new_str = cat_in_str(his_variable, line, new_line); printf("%s\n", new_str); free(new_line); @@ -158,8 +155,8 @@ 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 = NULL; - char *new_str = NULL; + char *new_line = nullptr; + char *new_str = nullptr; if (!his_command[id].arg) new_line = " "; From cd217d95ab1e77cd99f2297c8ac5f71ded9702da Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 18:47:54 +0200 Subject: [PATCH 31/46] Refactor others --- src/builtins/builtins_alias.c | 13 ++++++------- src/builtins/exit.c | 2 +- src/builtins/unset.c | 8 +++----- src/visitor.c | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/builtins/builtins_alias.c b/src/builtins/builtins_alias.c index a291630..65d8906 100644 --- a/src/builtins/builtins_alias.c +++ b/src/builtins/builtins_alias.c @@ -4,15 +4,14 @@ ** File description: ** history */ -#include -#include -#include -#include -#include "common.h" -#include "env.h" -#include "exec.h" +#include +#include +#include + #include "alias.h" +#include "common.h" +#include "exec.h" #include "utils.h" void free_alias(alias_t *alias) diff --git a/src/builtins/exit.c b/src/builtins/exit.c index 881909a..6324891 100644 --- a/src/builtins/exit.c +++ b/src/builtins/exit.c @@ -12,7 +12,7 @@ #include "env.h" #include "exec.h" -int builtins_exit(ef_t *ef, char **args __attribute__((unused))) +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)) diff --git a/src/builtins/unset.c b/src/builtins/unset.c index ced6864..9944e6c 100644 --- a/src/builtins/unset.c +++ b/src/builtins/unset.c @@ -5,14 +5,12 @@ ** unset */ -#include -#include -#include -#include #include +#include +#include +#include #include "common.h" -#include "env.h" #include "exec.h" #include "u_str.h" diff --git a/src/visitor.c b/src/visitor.c index cfab9f2..4c4217a 100644 --- a/src/visitor.c +++ b/src/visitor.c @@ -200,7 +200,7 @@ int visitor(char *buffer, exec_ctx_t *exec_ctx) return RETURN_FAILURE; result = visitor_launcher(&ef); if (ef.flags & F_EXIT) - builtins_exit(&ef, NULL); + builtins_exit(&ef, nullptr); free_ast(&ctx); return result == -1 ? RETURN_FAILURE : result; } From bcb26c89c75daa77698f5ca9692e706b0abcd69c Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 19:34:23 +0200 Subject: [PATCH 32/46] Add basic ~ --- src/args.c | 19 +++++++++++++++++++ src/ast.h | 7 ++++--- src/ast/ast.c | 2 +- src/ast/tokeniser.c | 1 + src/builtins/cd.c | 4 ++-- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/args.c b/src/args.c index b25b0b4..84cf526 100644 --- a/src/args.c +++ b/src/args.c @@ -47,6 +47,23 @@ bool process_globbing(char *pattern, args_t *args, size_t *toks_i) return true; } +static +bool handle_tilde(ef_t *ef, args_t *args, size_t *toks_i) +{ + char *home; + + if (!ensure_args_capacity(args)) + return false; + home = get_env_value(ef->env, "HOME"); + if (home != NULL) + args->args[args->sz] = get_env_value(ef->env, "HOME"); + else + args->args[args->sz] = strdup(""); + args->sz++; + *toks_i += 1; + 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]; @@ -55,6 +72,8 @@ bool process_args(ast_t *node, args_t *args, size_t *toks_i, ef_t *ef) return false; if (tok.type == T_STAR || strcspn(tok.str, "[]?") != strlen(tok.str)) return (process_globbing(tok.str, args, toks_i)); + if (tok.type == T_TILDE) + return handle_tilde(ef, args, toks_i); handle_var_case(node, ef->exec_ctx, toks_i, args); if (args->args[args->sz] == NULL) return false; diff --git a/src/ast.h b/src/ast.h index b0ca08b..39bb089 100644 --- a/src/ast.h +++ b/src/ast.h @@ -39,9 +39,10 @@ typedef enum size_t { T_STAR = 1 << 18, // * T_BACKSLASH = 1 << 19, T_NEWLINE = 1 << 20, // \n - T_EOF = 1 << 21, // \0 - T_ARG = 1 << 22, - T_INVALID = 1 << 23 + T_TILDE = 1 << 21, // ~ + T_EOF = 1 << 22, // \0 + T_ARG = 1 << 23, + T_INVALID = 1 << 24 } token_type_t; typedef enum { diff --git a/src/ast/ast.c b/src/ast/ast.c index f0fa0ac..57aaabb 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -27,7 +27,7 @@ ast_t *parse_arg(ast_ctx_t *ctx, ast_t *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_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; diff --git a/src/ast/tokeniser.c b/src/ast/tokeniser.c index 9d8660f..c3f3e75 100644 --- a/src/ast/tokeniser.c +++ b/src/ast/tokeniser.c @@ -30,6 +30,7 @@ const tokens_list_t TOKENS_LIST[] = { { T_IN_REDIRECT, "<", 1, "T_IN_REDIRECT" }, { T_BACKSLASH, "\\", 1, "T_BACKSLASH" }, { T_NEWLINE, "\n", 1, "T_NEWLINE"}, + { T_TILDE, "~", 1, "T_TILDE"}, { T_STAR, "*", 1, "T_STAR"}, { T_EOF, "\0", 1, "T_EOF" } }; diff --git a/src/builtins/cd.c b/src/builtins/cd.c index f888618..0f5e68f 100644 --- a/src/builtins/cd.c +++ b/src/builtins/cd.c @@ -43,7 +43,7 @@ char *get_current_dir(void) size_t max_it = 100; if (!buffer) - return NULL; + return nullptr; while (getcwd(buffer, size) == NULL && max_it > 0) { if (errno != ERANGE) return (free(buffer), NULL); @@ -82,7 +82,7 @@ int builtins_cd(ef_t *ef, char **args) if (!(ef->out_fd == STDOUT_FILENO || ef->p_i == ef->p_sz - 1)) return RETURN_SUCCESS; - if (path == NULL || u_strcmp(args[1], "~") == 0) + if (path == NULL) path = get_env_value(ef->env, "HOME"); if (path == NULL) return RETURN_FAILURE; From 4cc590c8d938aa470658411a27f944fb603198ef Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 19:40:36 +0200 Subject: [PATCH 33/46] Refactor alias Refactor alias --- src/alias.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/alias.c b/src/alias.c index d67ee6d..786d4e5 100644 --- a/src/alias.c +++ b/src/alias.c @@ -17,7 +17,7 @@ #include "utils.h" static -int skip_blank(char *buffer, int i) +int skip_blank(const char *buffer, int i) { for (; buffer[i] != 0 && isblank(buffer[i]); i++); return i; @@ -26,7 +26,7 @@ int skip_blank(char *buffer, int i) static int skip_to_next_token(char *buffer, int i) { - for (; buffer[i] != 0 && is_a_token(buffer, i) == false; i++); + for (; buffer[i] != 0 && !is_a_token(buffer, i); i++); return i; } @@ -34,17 +34,17 @@ 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 = NULL; + char *new_cmd = nullptr; if (cmd == NULL) - return 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 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; @@ -59,10 +59,10 @@ char *get_alias(char *buffer, int i, alias_t *alias) { int coord = i; int size = 0; - his_variable_t variable = {0, 0, 0, NULL, 0}; + his_variable_t variable = {0, 0, 0, nullptr, 0}; for (; buffer[i] != 0 && !isblank(buffer[i]) - && is_a_token(buffer, i) == false; i++) + && !is_a_token(buffer, i); i++) size++; variable.coord_variable = coord; variable.size_variable = size; @@ -90,7 +90,7 @@ int parse_alias(char **buffer, size_t *buffer_len, alias_t *alias) { bool need_to_replace = true; - while (need_to_replace == true) + while (need_to_replace) need_to_replace = replace_alias(buffer, alias); return RETURN_SUCCESS; } @@ -104,8 +104,8 @@ alias_t init_alias(void) alias.alias_to_replace = malloc(sizeof(char *) * alias.size); if (!alias.alias_array || !alias.alias_to_replace) return alias; - alias.alias_array[0] = NULL; - alias.alias_to_replace[0] = NULL; + alias.alias_array[0] = nullptr; + alias.alias_to_replace[0] = nullptr; alias.size = 0; return alias; } From c5e2fe18584deba843ba4f5230cead18784b029b Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 19:44:30 +0200 Subject: [PATCH 34/46] Move parse condition in conditions.c --- src/ast.h | 1 + src/ast/ast.c | 24 ++++++++---------------- src/ast/conditions.c | 36 ++++++++++++++++++++++++------------ 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/ast.h b/src/ast.h index 39bb089..aa0002b 100644 --- a/src/ast.h +++ b/src/ast.h @@ -143,4 +143,5 @@ 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 */ diff --git a/src/ast/ast.c b/src/ast/ast.c index 57aaabb..4834f71 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -14,12 +14,20 @@ #include "ast.h" +static +bool parse_special_args(ast_ctx_t *ctx, ast_t *node) +{ + 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, node)) + return nullptr; if (ctx->act_tok.type == T_BACKSLASH) { ctx->act_tok = get_next_token(ctx); if (ctx->act_tok.type == T_EOF) @@ -108,22 +116,6 @@ ast_t *parse_pipe(ast_ctx_t *ctx, ast_t *l_node) return 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; -} - ast_t *parse_semi(ast_ctx_t *ctx) { ast_t *l_node = parse_condition_and(ctx); diff --git a/src/ast/conditions.c b/src/ast/conditions.c index e0879a1..27df329 100644 --- a/src/ast/conditions.c +++ b/src/ast/conditions.c @@ -57,6 +57,22 @@ ast_t *parse_condition_and(ast_ctx_t *ctx) 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) { @@ -65,9 +81,7 @@ bool fill_else_node(ast_ctx_t *ctx, ast_t *node, buff_t *buff) if (node->cond.nodes2[node->cond.sz2] == NULL) return false; node->cond.sz2++; - if (!ensure_cond_cap2(node)) - return false; - return true; + return ensure_cond_cap2(node); } static @@ -82,15 +96,13 @@ bool fill_if_node(ast_ctx_t *ctx, ast_t *node, bool fill_else, buff_t *buff) if (node->cond.nodes[node->cond.sz] == NULL) return false; node->cond.sz++; - if (!ensure_cond_cap(node)) - return false; - return true; + return ensure_cond_cap(node); } static ast_t *fill_if(ast_ctx_t *ctx, ast_t *node) { - buff_t buff = { .str = NULL, 0 }; + buff_t buff = { .str = nullptr, 0 }; char *old_buff = ctx->str; bool fill_else = false; @@ -98,15 +110,15 @@ ast_t *fill_if(ast_ctx_t *ctx, ast_t *node) if (isatty(STDIN_FILENO)) WRITE_CONST(STDOUT_FILENO, IF_PROMPT); if (getline(&buff.str, &buff.sz, stdin) < 0) - return NULL; + 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 NULL; - buff = (buff_t){ .str = NULL, 0 }; + return nullptr; + buff = (buff_t){ .str = nullptr, 0 }; } ctx->str = old_buff; return node; @@ -117,7 +129,7 @@ ast_t *parse_if(ast_ctx_t *ctx) ast_t *node = create_node(ctx); if (node == NULL) - return NULL; + return nullptr; node->tok = ctx->act_tok; node->type = N_COND; node->cond.cap = DEFAULT_N_COND_CAP; @@ -128,7 +140,7 @@ ast_t *parse_if(ast_ctx_t *ctx) node->cond.nodes2 = (ast_t **)malloc(sizeof *node->cond.nodes * node->cond.cap2); if ((void *)node->cond.nodes == NULL || (void *)node->cond.nodes2 == NULL) - return NULL; + return nullptr; node->cond.exp = parse_semi(ctx); if (node->cond.exp == NULL) return WRITE_CONST(STDERR_FILENO, "if: Too few arguments.\n"), NULL; From c6976ce0e380262ecc7c6d118b18aa71ffc5ad9d Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 20:04:35 +0200 Subject: [PATCH 35/46] Remove unused include in utils --- src/builtins/builtin_history.c | 1 + src/utils.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/builtins/builtin_history.c b/src/builtins/builtin_history.c index e87cef2..8389433 100644 --- a/src/builtins/builtin_history.c +++ b/src/builtins/builtin_history.c @@ -12,6 +12,7 @@ #include #include "history.h" +#include "u_str.h" #include "utils.h" /* diff --git a/src/utils.h b/src/utils.h index 3431f06..e79f370 100644 --- a/src/utils.h +++ b/src/utils.h @@ -9,10 +9,10 @@ #ifndef UTILS_H #define UTILS_H #include "history.h" - #include "u_str.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); #endif /* UTILS_H */ From 5f1c4c53f6ad875081f9e8cc2bd48437b2a26df7 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 20:04:41 +0200 Subject: [PATCH 36/46] Add tilde handling --- src/args.c | 17 +++++++++++++---- src/ast/ast.c | 8 ++++++-- src/ast/tokeniser.c | 2 -- src/utils/insert_str.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 src/utils/insert_str.c diff --git a/src/args.c b/src/args.c index 84cf526..07f6d2f 100644 --- a/src/args.c +++ b/src/args.c @@ -13,7 +13,9 @@ #include #include "args.h" +#include "debug.h" #include "exec.h" +#include "utils.h" bool check_glob_result(int val, char *bin_name) { @@ -48,17 +50,24 @@ bool process_globbing(char *pattern, args_t *args, size_t *toks_i) } static -bool handle_tilde(ef_t *ef, args_t *args, size_t *toks_i) +bool handle_tilde(ef_t *ef, token_t *tok, args_t *args, size_t *toks_i) { char *home; + char *final_str; + size_t tilde_pos = strcspn(tok->str, "~"); + tok->str[tok->sz] = '\0'; if (!ensure_args_capacity(args)) return false; home = get_env_value(ef->env, "HOME"); if (home != NULL) - args->args[args->sz] = get_env_value(ef->env, "HOME"); + final_str = get_env_value(ef->env, "HOME"); else - args->args[args->sz] = strdup(""); + 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++; *toks_i += 1; return true; @@ -73,7 +82,7 @@ bool process_args(ast_t *node, args_t *args, size_t *toks_i, ef_t *ef) if (tok.type == T_STAR || strcspn(tok.str, "[]?") != strlen(tok.str)) return (process_globbing(tok.str, args, toks_i)); if (tok.type == T_TILDE) - return handle_tilde(ef, args, toks_i); + return handle_tilde(ef, &tok, args, toks_i); handle_var_case(node, ef->exec_ctx, toks_i, args); if (args->args[args->sz] == NULL) return false; diff --git a/src/ast/ast.c b/src/ast/ast.c index 4834f71..69d9513 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -15,8 +15,12 @@ #include "ast.h" static -bool parse_special_args(ast_ctx_t *ctx, ast_t *node) +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; } @@ -26,7 +30,7 @@ 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, node)) + if (!parse_special_args(ctx)) return nullptr; if (ctx->act_tok.type == T_BACKSLASH) { ctx->act_tok = get_next_token(ctx); diff --git a/src/ast/tokeniser.c b/src/ast/tokeniser.c index c3f3e75..448f1c6 100644 --- a/src/ast/tokeniser.c +++ b/src/ast/tokeniser.c @@ -30,8 +30,6 @@ const tokens_list_t TOKENS_LIST[] = { { T_IN_REDIRECT, "<", 1, "T_IN_REDIRECT" }, { T_BACKSLASH, "\\", 1, "T_BACKSLASH" }, { T_NEWLINE, "\n", 1, "T_NEWLINE"}, - { T_TILDE, "~", 1, "T_TILDE"}, - { T_STAR, "*", 1, "T_STAR"}, { T_EOF, "\0", 1, "T_EOF" } }; diff --git a/src/utils/insert_str.c b/src/utils/insert_str.c new file mode 100644 index 0000000..baf6f51 --- /dev/null +++ b/src/utils/insert_str.c @@ -0,0 +1,29 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#include +#include +#include + +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; +} From ca999079b041a3445f82fdb534ade6e989d0280c Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 20:10:59 +0200 Subject: [PATCH 37/46] Fix tilde first arg --- src/ast/ast.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ast/ast.c b/src/ast/ast.c index 69d9513..9abf6d6 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -62,6 +62,8 @@ ast_t *fill_cmd_node(ast_ctx_t *ctx) 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; From d6b88e2ab63cdc3c8e202b01b077a4ecedbfe53b Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 20:11:07 +0200 Subject: [PATCH 38/46] Fix tilde skip others args --- src/args.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/args.c b/src/args.c index 07f6d2f..8f2f130 100644 --- a/src/args.c +++ b/src/args.c @@ -50,7 +50,7 @@ bool process_globbing(char *pattern, args_t *args, size_t *toks_i) } static -bool handle_tilde(ef_t *ef, token_t *tok, args_t *args, size_t *toks_i) +bool handle_tilde(ef_t *ef, token_t *tok, args_t *args) { char *home; char *final_str; @@ -69,7 +69,6 @@ bool handle_tilde(ef_t *ef, token_t *tok, args_t *args, size_t *toks_i) if (args->args[args->sz] == NULL) return false; args->sz++; - *toks_i += 1; return true; } @@ -82,7 +81,7 @@ bool process_args(ast_t *node, args_t *args, size_t *toks_i, ef_t *ef) if (tok.type == T_STAR || strcspn(tok.str, "[]?") != strlen(tok.str)) return (process_globbing(tok.str, args, toks_i)); if (tok.type == T_TILDE) - return handle_tilde(ef, &tok, args, toks_i); + return handle_tilde(ef, &tok, args); handle_var_case(node, ef->exec_ctx, toks_i, args); if (args->args[args->sz] == NULL) return false; From 6c0c446f3f0cc83dfed3e4f2250d7b92f0260cfa Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 20:11:10 +0200 Subject: [PATCH 39/46] Add tilde tests Fix tilde test --- validation_tests.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/validation_tests.py b/validation_tests.py index b6a002c..050ee07 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -39,7 +39,7 @@ TESTS = [ cmds=[ "/bin/ls\n", "/../bin/ls\n", - # "~/../../bin/sh --version\n", + "~/../../bin/ls\n", "fixtures/exec.sh\n", ], depends_on=("ARGS",) @@ -243,4 +243,13 @@ TESTS = [ ], depends_on=("ARGS",) ), + + Test( + key="TILDE", + name="tilde", + cmds=[ + "echo ~", + ], + depends_on=("ARGS",) + ), ] From 0f21c8c5722ccc1b2dee1409b3706fd60843c5e0 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 20:50:32 +0200 Subject: [PATCH 40/46] Fix globbing --- src/args.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/args.c b/src/args.c index 8f2f130..02d8ac7 100644 --- a/src/args.c +++ b/src/args.c @@ -33,6 +33,7 @@ bool process_globbing(char *pattern, args_t *args, size_t *toks_i) 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; @@ -45,7 +46,6 @@ bool process_globbing(char *pattern, args_t *args, size_t *toks_i) args->sz++; } globfree(&globs); - *toks_i += 1; return true; } @@ -57,8 +57,6 @@ bool handle_tilde(ef_t *ef, token_t *tok, args_t *args) size_t tilde_pos = strcspn(tok->str, "~"); tok->str[tok->sz] = '\0'; - if (!ensure_args_capacity(args)) - return false; home = get_env_value(ef->env, "HOME"); if (home != NULL) final_str = get_env_value(ef->env, "HOME"); @@ -78,8 +76,10 @@ bool process_args(ast_t *node, args_t *args, size_t *toks_i, ef_t *ef) if (!ensure_args_capacity(args)) return false; - if (tok.type == T_STAR || strcspn(tok.str, "[]?") != strlen(tok.str)) + if (tok.type == T_STAR || strcspn(tok.str, "[]?") != strlen(tok.str)) { + 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); From 180b3fc1d5a4b53e7d1df329de8eda717663a768 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 20:56:11 +0200 Subject: [PATCH 41/46] Add globbing test --- validation_tests.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/validation_tests.py b/validation_tests.py index 050ee07..47136bf 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -252,4 +252,20 @@ TESTS = [ ], depends_on=("ARGS",) ), + + Test( + key="GLOB", + name="globbing", + cmds=[ + "ls *\n", + "echo *.nix\n", + "echo *file*\n", + "echo fixtures/*.sh\n", + "echo doesnotexist*\n", + "ls *.c *.h\n", + "echo *.txt > out.txt\n", + "cat < out.txt\n", + ], + depends_on=("REDIR",) + ), ] From 3b20443950056e219646a4b692a03213226b7eaf Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 21:14:18 +0200 Subject: [PATCH 42/46] Fix which and add tests --- src/builtins/which.c | 9 ++++++--- validation_tests.py | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/builtins/which.c b/src/builtins/which.c index 618d8d3..fa0f3da 100644 --- a/src/builtins/which.c +++ b/src/builtins/which.c @@ -31,13 +31,15 @@ bool search_builtin(ef_t *ef, char *arg) if (u_strlen(BUILTINS[i].name) != (int)strlen(arg)) continue; if (u_strcmp(BUILTINS[i].name, arg) == 0) - return dprintf(ef->out_fd, "%s is a shell built-in\n", arg), true; + 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 is a shell built-in\n", arg), true; + return dprintf(ef->out_fd, "%s: shell built-in command.\n", arg), + true; } return false; } @@ -54,12 +56,13 @@ bool search_cmd(ef_t *ef, char *arg) 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: aliased to %s\n", arg, + 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; } diff --git a/validation_tests.py b/validation_tests.py index 47136bf..2350096 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -124,7 +124,7 @@ TESTS = [ "echo kek | grep kek\n", "ls | grep Makefile\n", "who | wc -l\n", - "ls | | cat\n", # Syntax error + "ls | | cat\n", ], depends_on=("ARGS",) ), @@ -268,4 +268,39 @@ TESTS = [ ], depends_on=("REDIR",) ), + + Test( + key="REPEAT", + name="repeat loop", + cmds=[ + "repeat 3 echo plop\n", + "repeat 3\n", + "repeat\n", + ], + depends_on=("ARGS",) + ), + + Test( + key="FOREACH", + name="foreach loop", + cmds=[ + "foreach i (1 2 3)\necho $i\nend\n", + "foreach i", + "foreach", + ], + depends_on=("ARGS",) + ), + + Test( + key="WHICH", + name="which/where commands", + cmds=[ + "which ls\n", + "which cd\n", + "alias ll ls\nwhere ll\n", + #"alias ll ls\nwhich ll\n", + ], + depends_on=("ALIAS",) + ), + ] From 40d2f6d7f62694bd2bbf2f70267c840cba294009 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 21:16:00 +0200 Subject: [PATCH 43/46] Add builtins tests --- validation_tests.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validation_tests.py b/validation_tests.py index 2350096..3629182 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -303,4 +303,14 @@ TESTS = [ depends_on=("ALIAS",) ), + Test( + key="BUILTIN_ERR", + name="invalid builtin usage", + cmds=[ + "cd too many args here\n", + "unsetenv\n", + "setenv ONLYKEY\n", + ], + depends_on=("CD", "ENV") + ), ] From 4ceec261b5105f1845f55fd99161a37ff8bda836 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 22:41:08 +0200 Subject: [PATCH 44/46] Change prompt cursor --- src/builtins/local.c | 1 + src/common.h | 8 ++++++-- src/main.c | 48 +++++++++++++++++++++++++++++++++++++++---- src/repl.c | 1 + src/shell.c | 3 ++- src/shell.h | 3 ++- src/utils.h | 2 ++ src/vt100_esc_codes.h | 3 +++ 8 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/builtins/local.c b/src/builtins/local.c index 46e7a5f..f30404d 100644 --- a/src/builtins/local.c +++ b/src/builtins/local.c @@ -11,6 +11,7 @@ #include #include +#include "builtins_handler.h" #include "common.h" #include "u_mem.h" #include "u_str.h" diff --git a/src/common.h b/src/common.h index 8b7c3de..7959c82 100644 --- a/src/common.h +++ b/src/common.h @@ -7,7 +7,7 @@ #ifndef COMMON_H #define COMMON_H - #include "exec.h" + #include #define PROMPT_HEADER "┌─[" #define IF_PROMPT "if? " @@ -17,5 +17,9 @@ enum { RETURN_FAILURE = 1 }; -void free_everything(exec_ctx_t *exec_ctx); +typedef struct { + uint8_t flags; + char *script_file; + char *cmd; +} opt_t; #endif /* COMMON_H */ diff --git a/src/main.c b/src/main.c index 3bf4d19..e525dab 100644 --- a/src/main.c +++ b/src/main.c @@ -5,12 +5,52 @@ ** _ */ +#include +#include + +#include "common.h" #include "debug.h" #include "shell.h" -int main(int ac __attribute__((unused)), char **av __attribute__((unused)), - char **env) +const char OPT_FLAGS[] = "hc:"; + +static +void print_usages(FILE *file, char *bin) { - U_DEBUG_MSG("Debug mode activated.\n"); - return shell(env); + 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 = 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 activated.\n"); + if (!parse_args(&opt, ac, av)) + return RETURN_FAILURE; + return shell(&opt, env); } diff --git a/src/repl.c b/src/repl.c index 41081e1..5dfcbf5 100644 --- a/src/repl.c +++ b/src/repl.c @@ -45,6 +45,7 @@ void init_shell_repl(exec_ctx_t *exec_ctx) signal(SIGINT, SIG_IGN); exec_ctx->is_running = true; if (isatty(STDIN_FILENO)) { + WRITE_CONST(STDOUT_FILENO, BLINKING_VERTICAL_CURSOR); tcgetattr(STDIN_FILENO, &repl_settings); exec_ctx->saved_term_settings = repl_settings; repl_settings.c_iflag = IXON; diff --git a/src/shell.c b/src/shell.c index 54ef44a..6a6f570 100644 --- a/src/shell.c +++ b/src/shell.c @@ -20,6 +20,7 @@ #include "repl.h" #include "shell.h" #include "u_str.h" +#include "utils.h" __attribute__((unused)) static @@ -119,7 +120,7 @@ bool error_in_init(exec_ctx_t *exec_ctx) return false; } -int shell(char **env_ptr) +int shell(opt_t *opt, char **env_ptr) { alias_t alias = init_alias(); env_t env = parse_env(env_ptr); diff --git a/src/shell.h b/src/shell.h index 9aea593..eea4258 100644 --- a/src/shell.h +++ b/src/shell.h @@ -7,6 +7,7 @@ #ifndef SHELL_H #define SHELL_H + #include "common.h" typedef struct { char **cmd_history; @@ -14,5 +15,5 @@ typedef struct { char *last_chdir; } history_t; -int shell(char **env); +int shell(opt_t *opt, char **env); #endif /* SHELL_H */ diff --git a/src/utils.h b/src/utils.h index e79f370..703c7cb 100644 --- a/src/utils.h +++ b/src/utils.h @@ -9,10 +9,12 @@ #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 */ diff --git a/src/vt100_esc_codes.h b/src/vt100_esc_codes.h index a2860b7..24dd8f3 100644 --- a/src/vt100_esc_codes.h +++ b/src/vt100_esc_codes.h @@ -11,6 +11,9 @@ #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" From 59d177447508fdc912f828b2daa5a546c1d6fe38 Mon Sep 17 00:00:00 2001 From: savalet Date: Sun, 4 May 2025 23:02:04 +0200 Subject: [PATCH 45/46] Remove banned func list --- afunc.txt | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 afunc.txt diff --git a/afunc.txt b/afunc.txt deleted file mode 100644 index 84736e7..0000000 --- a/afunc.txt +++ /dev/null @@ -1,36 +0,0 @@ -malloc -free -exit -opendir -readdir -closedir -getcwd -chdir -fork -stat -lstat -fstat -open -close -getline -strtok -strtok_r -read -write -execve -access -isatty -wait -wait-pid -wait3 -wait4 -signal -kill -getpid -strerror -perror -strsignal -pipe -dup -dup2 -stdin From d9a681f6c146b1b97242d583fef9ad18e21a74d9 Mon Sep 17 00:00:00 2001 From: savalet Date: Mon, 5 May 2025 00:00:38 +0200 Subject: [PATCH 46/46] Add load file arg --- src/builtins/get_loop_cmd.c | 13 ++++++++----- src/builtins/if.c | 7 ++++--- src/builtins/loop.c | 2 +- src/builtins_handler.h | 3 +++ src/loop.h | 5 ++++- src/readline.c | 13 +++++++------ src/readline.h | 2 +- src/repl.c | 3 ++- src/shell.c | 27 +++++++++++++++++++++------ 9 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/builtins/get_loop_cmd.c b/src/builtins/get_loop_cmd.c index b40c3ce..88d16d3 100644 --- a/src/builtins/get_loop_cmd.c +++ b/src/builtins/get_loop_cmd.c @@ -17,6 +17,7 @@ #include "common.h" #include "loop.h" +#include "repl.h" #include "u_mem.h" #include "u_str.h" @@ -62,9 +63,10 @@ usr_cmd_t *handle_end(usr_cmd_t *us, char const *prompt) } static -usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char const *prompt, size_t *bf_len) +usr_cmd_t *get_first_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr, + char const *prompt, size_t *bf_len) { - if (isatty(STDIN_FILENO)) + if (isatty(exec_ctx->read_fd)) printf("%s? ", prompt); usr->cmds[usr->sz] = nullptr; getline(&(usr->cmds[usr->sz]), bf_len, stdin); @@ -74,7 +76,8 @@ usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char const *prompt, size_t *bf_len) return usr; } -usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char const *prompt) +usr_cmd_t *get_usr_loop_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr_cmd, + char const *prompt) { size_t buffer_len; @@ -83,9 +86,9 @@ usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char const *prompt) usr_cmd->cmds = (char **)malloc(sizeof(char *) * usr_cmd->cap); if ((void *)usr_cmd->cmds == NULL) return nullptr; - usr_cmd = get_first_cmd(usr_cmd, prompt, &buffer_len); + 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(STDIN_FILENO)) + if (isatty(exec_ctx->read_fd)) printf("%s? ", prompt); if (usr_cmd->sz >= usr_cmd->cap) usr_cmd = buffers_realloc(usr_cmd); diff --git a/src/builtins/if.c b/src/builtins/if.c index a53fb58..aa115ea 100644 --- a/src/builtins/if.c +++ b/src/builtins/if.c @@ -14,6 +14,7 @@ #include "common.h" #include "debug.h" #include "exec.h" +#include "repl.h" #include "u_str.h" static @@ -87,13 +88,13 @@ bool handle_if_buff(if_ctx_t *ctx, cmd_block_t *then_blk, } static -bool read_if_blocks(if_ctx_t *ctx, cmd_block_t *then_blk, +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(STDIN_FILENO)) + 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; @@ -128,7 +129,7 @@ bool handle_if_logic(ef_t *ef, bool cond, char *last) return cond ? visitor(last, ef->exec_ctx), true : true; if (!init_block(&then_blk) || !init_block(&else_blk)) return false; - if (!read_if_blocks(&ctx, &then_blk, &else_blk)) + if (!read_if_blocks(ef, &ctx, &then_blk, &else_blk)) return false; if (cond) exec_block(&then_blk, ef); diff --git a/src/builtins/loop.c b/src/builtins/loop.c index e945852..7925195 100644 --- a/src/builtins/loop.c +++ b/src/builtins/loop.c @@ -128,7 +128,7 @@ void launch_loop(ef_t *ef, char **args, char const *prompt) usr_cmds->sz = 0; signal(SIGINT, exit_child); signal(EOF, exit_child); - usr_cmds = get_usr_loop_cmd(usr_cmds, prompt); + 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); diff --git a/src/builtins_handler.h b/src/builtins_handler.h index ac137a9..5bb4fa5 100644 --- a/src/builtins_handler.h +++ b/src/builtins_handler.h @@ -24,6 +24,9 @@ typedef struct { bool is_running; struct termios saved_term_settings; local_t *local; + opt_t *opt; + int read_fd; + int isatty; } exec_ctx_t; size_t update_command(char **buffer, diff --git a/src/loop.h b/src/loop.h index 84c72f0..3832047 100644 --- a/src/loop.h +++ b/src/loop.h @@ -10,11 +10,14 @@ #include #include + #include "exec.h" + typedef struct { size_t sz; size_t cap; char **cmds; } usr_cmd_t; -usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char const *prompt); +usr_cmd_t *get_usr_loop_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr_cmd, + char const *prompt); #endif /* LOOP_H */ diff --git a/src/readline.c b/src/readline.c index 02c10ea..f6a845f 100644 --- a/src/readline.c +++ b/src/readline.c @@ -16,6 +16,7 @@ #include "common.h" #include "readline.h" +#include "debug.h" #include "repl.h" #include "u_str.h" @@ -70,13 +71,13 @@ bool ensure_buff_capacity(buff_t *buff) } static -bool append_null_terminator(buff_t *buff) +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(STDIN_FILENO)) + if (isatty(exec_ctx->read_fd)) WRITE_CONST(STDOUT_FILENO, "\n"); return true; } @@ -87,7 +88,7 @@ int8_t handle_line_buff(exec_ctx_t *exec_ctx, buff_t *buff, char *read_buff, { if (handle_keys(exec_ctx, buff, read_buff)) return RETURN_SUCCESS; - if (isatty(STDIN_FILENO) && str_printable(read_buff, read_size)) + 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; @@ -97,7 +98,7 @@ int8_t handle_line_buff(exec_ctx_t *exec_ctx, buff_t *buff, char *read_buff, return -1; } -bool readline(exec_ctx_t *exec_ctx, buff_t *buff) +bool readline(exec_ctx_t *exec_ctx, buff_t *buff, int fd) { char read_buff[2] = ""; ssize_t read_size = 0; @@ -106,7 +107,7 @@ bool readline(exec_ctx_t *exec_ctx, buff_t *buff) return false; while (strchr(read_buff, '\n') == NULL && *read_buff != '\r') { memset(read_buff, '\0', sizeof read_buff); - read_size = read(STDIN_FILENO, &read_buff, sizeof read_buff - 1); + read_size = read(fd, &read_buff, sizeof read_buff - 1); if (read_size < 0) return false; if (read_size == 0) @@ -114,5 +115,5 @@ bool readline(exec_ctx_t *exec_ctx, buff_t *buff) if (handle_line_buff(exec_ctx, buff, read_buff, read_size) > -1) return true; } - return append_null_terminator(buff); + return append_null_terminator(buff, exec_ctx); } diff --git a/src/readline.h b/src/readline.h index 940642f..ada2c11 100644 --- a/src/readline.h +++ b/src/readline.h @@ -13,5 +13,5 @@ #include "exec.h" #include "u_str.h" -bool readline(exec_ctx_t *exec_ctx, buff_t *buff); +bool readline(exec_ctx_t *exec_ctx, buff_t *buff, int fd); #endif /* READLINE */ diff --git a/src/repl.c b/src/repl.c index 5dfcbf5..8f961f1 100644 --- a/src/repl.c +++ b/src/repl.c @@ -12,6 +12,7 @@ #include "common.h" #include "exec.h" +#include "repl.h" #include "u_str.h" #include "vt100_esc_codes.h" @@ -44,7 +45,7 @@ void init_shell_repl(exec_ctx_t *exec_ctx) setvbuf(stdout, nullptr, _IONBF, 0); signal(SIGINT, SIG_IGN); exec_ctx->is_running = true; - if (isatty(STDIN_FILENO)) { + if (isatty(exec_ctx->read_fd)) { WRITE_CONST(STDOUT_FILENO, BLINKING_VERTICAL_CURSOR); tcgetattr(STDIN_FILENO, &repl_settings); exec_ctx->saved_term_settings = repl_settings; diff --git a/src/shell.c b/src/shell.c index 6a6f570..68ee13f 100644 --- a/src/shell.c +++ b/src/shell.c @@ -5,6 +5,7 @@ ** _ */ +#include #include #include #include @@ -58,7 +59,7 @@ bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx) size_t buffer_len; buff->sz = 0; - if (!readline(exec_ctx, buff)) + if (!readline(exec_ctx, buff, exec_ctx->read_fd)) return false; if (!buff->sz) return false; @@ -120,6 +121,19 @@ bool error_in_init(exec_ctx_t *exec_ctx) 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(); @@ -128,15 +142,16 @@ int shell(opt_t *opt, char **env_ptr) .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, - .history = &history, .history_command = cmd_history, .alias = &alias}; + 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 (error_in_init(&exec_ctx)) + if (exec_ctx.read_fd == -1 || (int)error_in_init(&exec_ctx)) return RETURN_FAILURE; U_DEBUG_CALL(debug_env_entries, &env); - shell_result = shell_loop(isatty(STDIN_FILENO), &exec_ctx); - if (isatty(STDIN_FILENO)) { + shell_result = shell_loop(isatty(exec_ctx.read_fd), &exec_ctx); + if (isatty(exec_ctx.read_fd)) { WRITE_CONST(STDOUT_FILENO, "exit\n"); restore_term_flags(&exec_ctx); }